C++ 与其他编程语言区别_C++11/14/17新特性总结

news2024/9/20 22:28:19

C++11

decltype类型推导

decltype不依赖于初始化,根据表达式类推导类型

  • auto b :根据右边a的初始值来推导出变量的类型,然后将该初始值赋给b
  • decltype 则是根据a表达式来推导类型,变量的初始值与表达式的值无关
  • 表达式类型注意点:如果表达式是左值,则推导出的类型也是左值引用

 

int a = 10;
auto b = a;
decltype(a) b = a; // b的类型是int



int add(int a, int b) {
    return a + b;
}

decltype(add(1, 2)) result; // result的类型是int


int x = 5;
int& ref = x;
decltype(ref) newRef = x; // newRef的类型是int&


int func(int a, int b) {
    return a + b;
}

decltype(&func) funcPtr = &func; // funcPtr的类型是int (*)(int, int)

bind

基本语法

  • callable:可以是函数指针、成员函数指针、函数对象或 lambda 表达式。
  • arg1, arg2, ..., argN:指定参数,可以是具体的值,也可以是占位符(例如 std::placeholders::_1
  • 占位符
    • 在使用 std::bind 时,可以使用占位符来表示绑定函数的参数位置。占位符定义在 std::placeholders 命名空间中,通常用 _1_2 等表示。例如:

    • std::placeholders::_1 表示绑定函数的第一个参数。
    • std::placeholders::_2 表示绑定函数的第二个参数
  • 注意
    • 参数绑定顺序std::bind 会按照传递给它的参数顺序进行绑定。占位符的编号必须与实际参数的位置相对应。
    • 捕获外部变量:使用 std::bind 时,可以将外部变量作为绑定参数传递,从而实现闭包效果。
    • 返回类型推导std::bind 创建的函数对象会自动推导返回类型,无需显式指定

绑定成员函数(常用) 

 

#include <iostream>
#include <functional>

class MyClass {
public:
    void print_message(const std::string& message) {
        std::cout << "Message: " << message << std::endl;
    }
};

int main() {
    MyClass my_object;
    // 绑定成员函数
    auto bound_member_function = std::bind(&MyClass::print_message, &my_object, std::placeholders::_1);
    bound_member_function("Hello, World!"); // 输出:Message: Hello, World!

    return 0;
}

绑定函数 

#include <iostream>
#include <functional>

void print_sum(int a, int b) {
    std::cout << "Sum: " << a + b << std::endl;
}

int main() {
    // 绑定参数到具体值
    auto bound_print = std::bind(print_sum, 5, 3);
    bound_print(); // 输出:Sum: 8

    // 使用占位符
    auto bound_print_with_placeholder = std::bind(print_sum, std::placeholders::_1, 10);
    bound_print_with_placeholder(5); // 输出:Sum: 15

    return 0;
}

绑定函数对象 

#include <iostream>
#include <functional>

struct Multiply {
    int operator()(int a, int b) const {
        return a * b;
    }
};

int main() {
    Multiply multiply;
    // 绑定函数对象
    auto bound_multiply = std::bind(multiply, std::placeholders::_1, 4);
    std::cout << "Product: " << bound_multiply(5) << std::endl; // 输出:Product: 20

    return 0;
}

范围for

  •  作用:遍历容器中的数据
  • 参数
    • declaration:用于声明每次迭代中从容器中提取的元素,可以是变量或引用。
    • expression:表示需要遍历的容器或范围
  • 注意点
    • 自动推导类型,可以使用auto关键字自动推导元素类型
    • 如果不需要修改容器中的元素,最后使用const声明元素,避免容器中的数据被修改
    • 范围:任何可以使用begin 和 end 的容器

 

事例代码 

 

#include <iostream>
#include <vector>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};

    // 使用引用遍历并修改元素
    for (int& elem : vec) {
        elem *= 2;
    }

    for (int elem : vec) {
        std::cout << elem << " ";
    }
    std::cout << std::endl;

    return 0;
}

右值引用

左值与右值

  • 左值:持久存储的对象,通常是变量
  • 右值:没有持久存储的临时对象,一般都是临时变量

用法:move可以显式的将一个左值转换为对应的右值引用类型

 

右值引用与移动语义结合事例代码

#include <iostream>
#include <vector>
#include <string>

class Resource {
public:
    std::string name;
    std::vector<int> data;

    Resource(const std::string& name) : name(name) {
        std::cout << "Constructing " << name << std::endl;
    }

    Resource(const Resource& other) : name(other.name), data(other.data) {
        std::cout << "Copy Constructing " << name << std::endl;
    }

    Resource(Resource&& other) noexcept : name(std::move(other.name)), data(std::move(other.data)) {
        std::cout << "Move Constructing " << name << std::endl;
    }

    Resource& operator=(Resource&& other) noexcept {
        if (this != &other) {
            name = std::move(other.name);
            data = std::move(other.data);
            std::cout << "Move Assigning " << name << std::endl;
        }
        return *this;
    }
};

int main() {
    Resource res1("Resource1");
    Resource res2("Resource2");

    // 触发移动构造函数
    Resource res3 = std::move(res1);

    // 触发移动赋值运算符
    res2 = std::move(res3);

    return 0;
}

标准库move函数

用法总结

  • 作用:将参数显式的转换为一个右值引用,使对象可以通过移动而不是复制的方式传递或者返回,从而提高程序性能(例如在动态内存等场景中,让资源空间移动,可以避免复制开辟空间的性能消耗
  • 理解:提供一个移动资源的方法
  • 实现:将其参数转换为右值引用

使用代码事例

#include <iostream>
#include <vector>
#include <utility> // for std::move

int main() {
    std::vector<int> v1 = { 1, 2, 3, 4, 5 };
    std::vector<int> v2;

    // 使用 std::move 将 v1 转换为右值引用,从而启用移动语义
    v2 = std::move(v1);

    // 现在 v1 应该是空的,v2 持有原先 v1 的资源
    std::cout << "v1 size: " << v1.size() << std::endl;
    std::cout << "v2 size: " << v2.size() << std::endl;

    return 0;
}

如果想要对象支持移动语义,则需要的为其定义移动构造函数以及移动赋值运算符 

class MyClass {
public:
    MyClass() : data(new int[100]) {}
    ~MyClass() { delete[] data; }

    // 移动构造函数
    MyClass(MyClass&& other) noexcept : data(other.data) {
        other.data = nullptr;
    }

    // 移动赋值运算符
    MyClass& operator=(MyClass&& other) noexcept {
        if (this != &other) {
            delete[] data;
            data = other.data;
            other.data = nullptr;
        }
        return *this;
    }

    // 禁用复制构造函数和复制赋值运算符
    MyClass(const MyClass&) = delete;
    MyClass& operator=(const MyClass&) = delete;

private:
    int* data;
};

禁用对象默认函数

C++11中如果不希望对象被复制,可以将复制构造函数以及复制赋值函数声明为delete来禁用,移动构造和移动赋值同样适用。C++11之前,可以将对象的默认函数放入私有域中,从而达到禁止使用默认函数的功能。

代码事例:C++11中的做法,以及private禁止默认函数的做法

class MyClass {
public:
    MyClass() = default;
    ~MyClass() = default;

    // 禁用复制构造函数
    MyClass(const MyClass&) = delete;

    // 禁用复制赋值运算符
    MyClass& operator=(const MyClass&) = delete;

    // 禁用移动构造函数
    MyClass(MyClass&&) = delete;

    // 禁用移动赋值运算符
    MyClass& operator=(MyClass&&) = delete;
};
class MyClass {
public:
    MyClass() {}
    ~MyClass() {}

private:
    // 禁用复制构造函数
    MyClass(const MyClass&);

    // 禁用复制赋值运算符
    MyClass& operator=(const MyClass&);

    // 禁用移动构造函数
    MyClass(MyClass&&);

    // 禁用移动赋值运算符
    MyClass& operator=(MyClass&&);
};

constexpr

该关键字用于指示表达式或者函数在编译的时候求职,用于定义常量表达式,从而提高程序的效率和安全性。

constexpr变量

  • 编译时求值的常量
  • constexpr确保在编译时进行求值,而const只可以确保值不能在运行中改变
constexpr int square(int x) {
    return x * x;
}

int main() {
    constexpr int a = 10;
    constexpr int b = square(a); // 在编译时求值
    int arr[b]; // 使用编译时常量作为数组大小
    return 0;
}

constexpr函数

  • 该函数是在编译时求值
  • 使用条件
    • 函数的返回类型以及参数必须是字面值类型
    • 函数体中只可以包含单一的return语句(注意,该规定在C++14中更改了)

constexpr int factorial(int n) {
    return (n <= 1) ? 1 : (n * factorial(n - 1));
}

int main() {
    constexpr int result = factorial(5); // 在编译时计算 5 的阶乘
    static_assert(result == 120, "Factorial calculation is incorrect");
    return 0;
}

constexpr 与 const的区别

  • const确保变量在运行的时候是只读的,但不一定在编译的时候求值
  • constexpr确保表达式在编译时求值,并且变量在运行的时候是只读 

const int a = 10; // 运行时常量
constexpr int b = 10; // 编译时常量

const int x = factorial(a); // 可以在运行时计算
constexpr int y = factorial(b); // 必须在编译时计算

初始化列表 initializer list

用法总结

  • 语法使用:直接初始化成员变量,而不用在构造函数体内赋值
  • 特点
    • 优化性能,减少性能开销
    • const成员变量必须通过初始化列表进行初始化,因为const成员变量在构造完成后不可以被赋值
    • 引用成员也必须通过初始化列表进行初始化
    • 顺序列表中的初始化的顺序必须和类中声明顺序一致
class MyClass {
public:
    MyClass(int a, int b) : x(a), y(b), z(a + b), ref(a) {}
private:
    const int x;
    int y;
    int z;
    int& ref;
};

nullptr

用法总结

  • 作用:C++11之前使用NULL宏来表示,NULL宏被定义为整数0,容易在上下文中引起歧义;nullptr则是一个指针字面值,专门用于表示空指针,不存在歧义问题
  • 优点
    • 类型安全:nullptr是一个指针类型,所以不会与整数类型混淆
    • 函数重载的时候,nullptr可以帮忙区分指针和整数参数

C++14

函数返回值类型推导

  • 作用:允许编译器根据函数返回语句,自动推导出返回类型,下面案例是自动推导出int类型
  • 注意
    • 单一返回类型:函数中所有返回语句必须是相同类型,否则编译器会报错
    • 返回引用和指针的时候,需要确保返回的对象在作用域中是否有效,避免悬空引用
#include <iostream>

auto add(int a, int b) {
    return a + b;
}

int main() {
    std::cout << add(2, 3) << std::endl; // 输出 5
    return 0;
}

lambda函数形参允许泛型

作用:无需预先指定参数类型,编译器根据lambda的使用情况自动推导参数的类型

 

事例案例理解 

#include <iostream>

int main() {
    auto add = [](auto x, auto y) {
        return x + y;
    };

    std::cout << add(1, 2) << std::endl;       // 输出 3
    std::cout << add(1.5, 2.5) << std::endl;   // 输出 4.0
    std::cout << add(std::string("Hello, "), std::string("World!")) << std::endl; // 输出 Hello, World!

    return 0;
}
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    int factor = 2;
    auto multiply = [factor](auto x) {
        return x * factor;
    };

    std::cout << multiply(3) << std::endl;    // 输出 6
    std::cout << multiply(3.5) << std::endl;  // 输出 7.0

    return 0;
}
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};

    auto print = [](const auto& container) {
        for (const auto& elem : container) {
            std::cout << elem << " ";
        }
        std::cout << std::endl;
    };

    print(vec); // 输出 1 2 3 4 5

    return 0;
}

变量模板

作用:类似于函数模板,但是是给变量使用的一种模板

#include <iostream>

template<typename T>
constexpr T pi = T(3.1415926535897932385);

int main() {
    std::cout << pi<float> << std::endl;  // 输出 3.14159
    std::cout << pi<double> << std::endl; // 输出 3.141592653589793
    std::cout << pi<long double> << std::endl; // 输出 3.1415926535897932385

    return 0;
}

常量模版,事例中是获取不同类型的最大值 

#include <iostream>

template<typename T>
constexpr T max_value = std::numeric_limits<T>::max();

int main() {
    std::cout << max_value<int> << std::endl;          // 输出 int 类型的最大值
    std::cout << max_value<unsigned int> << std::endl; // 输出 unsigned int 类型的最大值
    std::cout << max_value<double> << std::endl;       // 输出 double 类型的最大值

    return 0;
}

属性模版,下面事例展示用于计算的给定类型的平方根 

#include <iostream>
#include <cmath>

template<typename T>
constexpr T square(T x) {
    return x * x;
}

template<typename T>
constexpr T sqrt_value = std::sqrt(square(T(2)));

int main() {
    std::cout << sqrt_value<float> << std::endl;  // 输出 2.82843
    std::cout << sqrt_value<double> << std::endl; // 输出 2.82843
    std::cout << sqrt_value<long double> << std::endl; // 输出 2.82843

    return 0;
}

类模版和变量模板

#include <iostream>

template<typename T>
struct Traits {
    static constexpr T zero = T(0);
};

int main() {
    std::cout << Traits<int>::zero << std::endl;       // 输出 0
    std::cout << Traits<float>::zero << std::endl;     // 输出 0
    std::cout << Traits<double>::zero << std::endl;    // 输出 0

    return 0;
}

deprecated属性

作用:标记不建议使用的函数、变量或者类型,如果使用了,则编译的时候会报错

 标记函数被弃用

#include <iostream>

[[deprecated]]
void oldFunction() {
    std::cout << "This is an old function." << std::endl;
}

void newFunction() {
    std::cout << "This is a new function." << std::endl;
}

int main() {
    oldFunction(); // 编译时会产生警告
    newFunction(); // 正常调用
    return 0;
}

标记变量弃用 

#include <iostream>

[[deprecated("Use newVar instead")]]
int oldVar;

int newVar;

int main() {
    oldVar = 10; // 编译时会产生警告
    newVar = 20; // 正常使用
    std::cout << oldVar << std::endl;
    std::cout << newVar << std::endl;
    return 0;
}

标记类型弃用 

#include <iostream>

[[deprecated("Use NewStruct instead")]]
struct OldStruct {
    int value;
};

struct NewStruct {
    int value;
};

int main() {
    OldStruct oldInstance; // 编译时会产生警告
    oldInstance.value = 10;

    NewStruct newInstance;
    newInstance.value = 20;

    std::cout << oldInstance.value << std::endl;
    std::cout << newInstance.value << std::endl;
    return 0;
}

标记类的成员函数被弃用 

#include <iostream>

class MyClass {
public:
    [[deprecated("Use newMethod() instead")]]
    void oldMethod() {
        std::cout << "This is the old method." << std::endl;
    }

    void newMethod() {
        std::cout << "This is the new method." << std::endl;
    }
};

int main() {
    MyClass obj;
    obj.oldMethod(); // 编译时会产生警告
    obj.newMethod(); // 正常调用
    return 0;
}

std::make_unique

  • 作用:用于创建std::unique_ptr对象,以一种更安全高效的方式创建智能指针,避免new的内存泄漏风险
  • 优点
    • 避免内存泄漏
    • 类型安全:会自动推导出指针类型,减少类型错误的风险
  • 语法分析
    • T 是要创建的对象的类型。
    • Args&&... args 是传递给 T 的构造函数的参数

 创建一个对象:创建一个指向整数42的unique_ptr

#include <iostream>
#include <memory>

int main() {
    auto p = std::make_unique<int>(42);
    std::cout << *p << std::endl; // 输出 42
    return 0;
}

 创建动态数组

#include <iostream>
#include <memory>

int main() {
    auto p = std::make_unique<int[]>(5);
    for (int i = 0; i < 5; ++i) {
        p[i] = i * i;
    }

    for (int i = 0; i < 5; ++i) {
        std::cout << p[i] << " "; // 输出 0 1 4 9 16
    }
    std::cout << std::endl;

    return 0;
}

创建自定义对象

#include <iostream>
#include <memory>

class MyClass {
public:
    MyClass(int x) : x_(x) {
        std::cout << "MyClass constructed with " << x_ << std::endl;
    }
    ~MyClass() {
        std::cout << "MyClass destructed" << std::endl;
    }
    int getX() const { return x_; }

private:
    int x_;
};

int main() {
    auto p = std::make_unique<MyClass>(10);
    std::cout << p->getX() << std::endl; // 输出 10
    return 0;
}

C++17

结构化绑定

作用:通过简单的语法,实现将变量绑定到结构或者元祖的成员上

 

解构元组

#include <iostream>
#include <tuple>

std::tuple<int, double, std::string> getTuple() {
    return {1, 2.5, "hello"};
}

int main() {
    auto [x, y, z] = getTuple();
    std::cout << "x: " << x << ", y: " << y << ", z: " << z << std::endl;
    return 0;
}

解构结构体

#include <iostream>

struct Point {
    int x;
    int y;
};

int main() {
    Point p{10, 20};
    auto [x, y] = p;
    std::cout << "x: " << x << ", y: " << y << std::endl;
    return 0;
}

解构数组 

#include <iostream>

int main() {
    int arr[] = {1, 2, 3};
    auto [a, b, c] = arr;
    std::cout << "a: " << a << ", b: " << b << ", c: " << c << std::endl;
    return 0;
}

 与标准库结合使用

#include <iostream>
#include <map>

int main() {
    std::map<int, std::string> m = {{1, "one"}, {2, "two"}, {3, "three"}};

    for (const auto& [key, value] : m) {
        std::cout << "key: " << key << ", value: " << value << std::endl;
    }

    return 0;
}

if-switch语句初始化

含义:允许在if 和switch语句中进行初始化,从而让变量的作用域更加局部化(根据具体事例理解)

 if语句初始化(auto it ...初始化,只在if语句范围内有用)

 

#include <iostream>
#include <vector>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};

    if (auto it = std::find(vec.begin, vec.end(), 3); it != vec.end()) {
        std::cout << "Found 3 at index " << std::distance(vec.begin(), it) << std::endl;
    } else {
        std::cout << "3 not found" << std::endl;
    }

    return 0;
}

Switch语句初始化,也同样只在Switch语句范围内起作用 

#include <iostream>
#include <map>

enum class Color { RED, GREEN, BLUE };

int main() {
    std::map<std::string, Color> colorMap = {{"red", Color::RED}, {"green", Color::GREEN}, {"blue", Color::BLUE}};
    std::string colorStr = "green";

    switch (auto it = colorMap.find(colorStr); it != colorMap.end() ? it->second : Color::BLUE) {
        case Color::RED:
            std::cout << "Color is red" << std::endl;
            break;
        case Color::GREEN:
            std::cout << "Color is green" << std::endl;
            break;
        case Color::BLUE:
            std::cout << "Color is blue" << std::endl;
            break;
        default:
            std::cout << "Unknown color" << std::endl;
            break;
    }

    return 0;
}

constexpr lambda表达式

总结

  • 该lambda表达式可以在编译的时候进行常量计算,从而提高代码效率和安全性。
  • 注意
    • 表达式限制: constexpr lambda表达式中的代码必须符合constexpr函数的要求
    • 常量上下文:该lambda表达式必须能够在编译的时候计算

#include <iostream>

constexpr auto add = [](int a, int b) constexpr {
    return a + b;
};

int main() {
    constexpr int result = add(3, 4); // 在编译时计算
    std::cout << "Result: " << result << std::endl; // 输出 7
    return 0;
}

常量计算 

#include <iostream>
#include <array>

constexpr auto square = [](int x) constexpr {
    return x * x;
};

int main() {
    constexpr int value = 5;
    constexpr int result = square(value); // 在编译时计算

    std::array<int, result> arr; // 使用计算结果作为数组大小

    std::cout << "Array size: " << arr.size() << std::endl; // 输出 25
    return 0;
}

与标准库结合使用的场景 

#include <iostream>
#include <algorithm>
#include <array>

int main() {
    constexpr auto greater = [](int a, int b) constexpr {
        return a > b;
    };

    std::array<int, 5> arr = {5, 2, 3, 4, 1};
    std::sort(arr.begin(), arr.end(), greater); // 在运行时排序

    for (const auto& elem : arr) {
        std::cout << elem << " "; // 输出 5 4 3 2 1
    }
    std::cout << std::endl;

    return 0;
}

namespace嵌套

基于语法结构

#include <iostream>

namespace Outer {
    int outerVar = 10;
    
    namespace Inner {
        int innerVar = 20;
        
        class InnerClass {
        public:
            void display() {
                std::cout << "Outer variable: " << outerVar << std::endl;
                std::cout << "Inner variable: " << innerVar << std::endl;
            }
        };
    }
}

int main() {
    Outer::Inner::InnerClass obj;
    obj.display();
    return 0;
}

#include <iostream>

namespace Outer {
    int outerVar = 10;
    
    namespace Inner {
        int innerVar = 20;
        
        class InnerClass {
        public:
            void display() {
                std::cout << "Outer variable: " << outerVar << std::endl;
                std::cout << "Inner variable: " << innerVar << std::endl;
            }
        };
    }
}

int main() {
    Outer::Inner::InnerClass obj;
    obj.display();
    return 0;
}

std::any

总结

  • 含义:提供一种类型安全的方式来存储和操作任意类型的值(可以理解成动态语言中的万能类型)
  • 使用场景:用来代替一些需要存储不同类型对象的场景
  • 事例代码
    • 定义和使用any类型定义的数值
    • 访问存储的数值
    • 检查any中的类型(type())
#include <iostream>
#include <any>

int main() {
    std::any a = 1; // 存储 int 类型
    std::cout << std::any_cast<int>(a) << std::endl;

    a = 3.14; // 存储 double 类型
    std::cout << std::any_cast<double>(a) << std::endl;

    a = std::string("Hello, std::any!"); // 存储 std::string 类型
    std::cout << std::any_cast<std::string>(a) << std::endl;

    return 0;
}
#include <iostream>
#include <any>

int main() {
    std::any a = 10;

    try {
        int value = std::any_cast<int>(a);
        std::cout << "Value: " << value << std::endl;
    } catch (const std::bad_any_cast& e) {
        std::cout << "Bad any_cast: " << e.what() << std::endl;
    }

    return 0;
}
#include <iostream>
#include <any>
#include <typeinfo>

int main() {
    std::any a = 10;

    if (a.type() == typeid(int)) {
        std::cout << "a contains an int" << std::endl;
    } else {
        std::cout << "a does not contain an int" << std::endl;
    }

    return 0;
}

std::basic_string_view

总结

  • 作用:轻量级、非拥有的字符串视图类型,对字符串只读访问,也就是只查看字符串指定内容,不需要复制或者拥有字符串的实际数据
  • 特点
    • 轻量级:只是一个视图,不拥有数据,所以构造和赋值的性能开销小
    • 无拷贝:因为不需要数据,所以不会进行数据拷贝
    • 灵活:可以按照自己的需要灵活拷贝字符串
#include <iostream>
#include <string_view>

void printString(std::string_view sv) {
    std::cout << sv << std::endl;
}

int main() {
    std::string str = "Hello, std::string_view!";
    printString(str); // 传递 std::string
    printString("Hello, world!"); // 传递字符串字面量
    printString(str.substr(7, 12)); // 传递 std::string 的子字符串
    return 0;
}

//基本操作

#include <iostream>
#include <string_view>

int main() {
    std::string_view sv = "Hello, world!";
    
    std::cout << "Length: " << sv.length() << std::endl; // 输出长度
    std::cout << "First character: " << sv.front() << std::endl; // 输出第一个字符
    std::cout << "Last character: " << sv.back() << std::endl; // 输出最后一个字符
    std::cout << "Substring: " << sv.substr(7, 5) << std::endl; // 输出子字符串 "world"

    // 查找子字符串
    size_t pos = sv.find("world");
    if (pos != std::string_view::npos) {
        std::cout << "\"world\" found at position " << pos << std::endl;
    }

    return 0;
}

#include <iostream>
#include <string_view>

int main() {
    std::string_view sv = "Hello, world!";
    
    std::cout << "Length: " << sv.length() << std::endl; // 输出长度
    std::cout << "First character: " << sv.front() << std::endl; // 输出第一个字符
    std::cout << "Last character: " << sv.back() << std::endl; // 输出最后一个字符
    std::cout << "Substring: " << sv.substr(7, 5) << std::endl; // 输出子字符串 "world"

    // 查找子字符串
    size_t pos = sv.find("world");
    if (pos != std::string_view::npos) {
        std::cout << "\"world\" found at position " << pos << std::endl;
    }

    return 0;
}

C和C++

相同点

  • 基本语法结构,循环控制函数定义都类似
  • 基本数据结构
  • C中的标准库函数在C++中同样适用
  • 指针与数组使用方法类似
  • 预处理指令

不同点

  • 面向对象:C++支持面向对象
  • 函数与运算符重载:C++支持,C不支持
  • 模板:C++支持
  • C++支持STL标准库
  • 两者的内存管理不同C++有异常处理机制,但是C没有

Java和C++

相同点

  • 面向对象编程

    • 两者都支持面向对象编程,包括类、继承、多态、封装等概念。
  • 语法结构

    • 两者的基本语法结构相似,如 if-elsefor 循环、while 循环、switch 语句等
  • 基本数据类型

    • 都有基本数据类型,如 intcharfloatdouble 等。
  • 标准库支持

    • 两者都提供了丰富的标准库,用于字符串操作、输入输出、集合等

不同点

  • 内存管理

    • C++ 需要手动进行内存管理,使用 newdelete 进行动态内存分配和释放。
    • Java 有垃圾回收机制,自动管理内存。
  • 平台独立性

    • C++ 编译生成的可执行文件是平台相关的。
    • Java 编译生成字节码,运行在 Java 虚拟机(JVM)上,实现平台独立性。
  • 多重继承

    • C++ 支持多重继承。
    • Java 不支持多重继承,但可以通过接口实现类似效果。
  • 指针

    • C++ 直接支持指针。
    • Java 不直接支持指针,提供了引用类型。
  • 异常处理

    • Java 强制使用异常处理,许多库函数都会抛出异常。
    • C++ 提供异常处理机制,但使用不如 Java 强制。
  • 模板与泛型

    • C++ 使用模板实现泛型编程。
    • Java 使用泛型,但类型信息在运行时会被擦除(类型擦除)

Python和C++

相同点

  • 支持面向对象编程

    • 两者都支持面向对象编程。
  • 丰富的标准库

    • 两者都提供了丰富的标准库支持多种功能

不同点

  • 语法和易用性

    • Python 语法简单易读,强调代码的可读性。
    • C++ 语法复杂,更加灵活,但也更容易出现错误。
  • 性能

    • C++ 是编译型语言,性能高,适合对性能要求高的系统编程。
    • Python 是解释型语言,性能较低,但开发速度快,适合快速开发和脚本编写。
  • 内存管理

    • C++ 手动管理内存。
    • Python 有自动垃圾回收机制。
  • 类型系统

    • C++ 是静态类型语言,编译时检查类型。
    • Python 是动态类型语言,运行时检查类型。
  • 并发与并行

    • C++ 提供了多线程和多进程的并发机制。
    • Python 也支持多线程和多进程,但由于全局解释器锁(GIL)的存在,多线程性能受限,多进程更常用。
  • 应用领域

    • C++ 常用于系统编程、游戏开发、嵌入式系统等。
    • Python 常用于数据分析、机器学习、Web 开发、自动化脚本等

Go和C++

相同点

  • 编译型语言:源代码在执行前需要编译成可执行文件
  • 编译时对类型进行检查
  • 支持标准库,比如文件操作或者网络编程等

不同点

  •  语法
    • Go语法简洁,代码可读性高
    • C++语法复杂,功能强大,但是容易导致代码冗长难以维护
  • 内存管理
    • Go有垃圾回收机制,自动管理内存
    • C++需要手动管理内存
  • 并发编程
    • Go内置强大的并发支持,可以通过goroutines和channels实现并发
    • C++的多线程编程较为麻烦
  • 编译时间
    • Go变异速度快,适合快速开发和部署
    • C++编译速度慢
  • 错误处理

    • Go 使用显式错误处理,通过返回值和 error 类型处理错误。
    • C++ 使用异常处理机制,通过 try-catch 块捕获和处理异常。
  • 面向对象编程

    • C++ 是面向对象语言,支持类、继承、多态等特性。
    • Go 支持面向对象编程,但没有类和继承,使用结构体和接口实现类似功能

Rust和C++

相同点

  •  编译型语言,代码执行前都需要编译成可执行文件
  • 强类型检查,编译的时候都会进行类型检查
  • 都对底层硬件和内存进行精细控制,适合系统编程和高性能应用

不同点

  • 内存管理
    • C++需要程序员管理内存,通常需要使用new和delete进行动态内存分配和释放
    • Rust则使用所有权系统和借助检查器管理内存,编译的时候保证内存安全,无需垃圾回收
  • 并发编程
    • Rust提供了安全的并发编程,通过所有权和类型系统在编译的时候防止数据竞争
    • C++支持多线程编程,但是需要使用更复杂的线程库和同步机制
  •  错误处理
    • Rust使用显式错误处理,通过Result和Option类型来处理错误
    • C++使用异常处理机制,通过try-catch模块来捕捉异常
  • 面向对象
    • C++支持面向对象语言,支持类、继承、多态等
    • Rust则不支持传统的面向对象编程,但是提供结构体和特征来实现类似功能 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1967555.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

React组件生命周期

一张图解释 React 类组件生命周期方法 React 类组件的生命周期可以分为三个主要阶段&#xff1a; 挂载&#xff08;Mounting&#xff09; 更新&#xff08;Updating&#xff09; 卸载&#xff08;Unmounting&#xff09; 挂载阶段 在组件实例被创建并插入到 DOM 中时调用…

目标检测 | yolov1 原理和介绍

简介 论文链接&#xff1a;https://arxiv.org/abs/1506.02640 时间&#xff1a;2015年 作者&#xff1a;Joseph Redmon 代码参考&#xff1a;https://github.com/abeardear/pytorch-YOLO-v1 yolo属于one-stage算法&#xff0c;仅仅使用一个CNN网络直接预测不同目标的类别与位置…

Transformer 会彻底改变时间序列预测吗?

欢迎来到雲闪世界。“生成式人工智能革命”的核心是谷歌于 2017 年推出的 Transformer 模型。 但每一次技术革命都会带来混乱。在快速增长的环境中&#xff0c;很难公正地评估创新——更不用说估计其影响了。 开启人工智能这一突破的Transformer模型&#xff0c;如今已成为一…

【Linux】文件描述符 fd

目录 一、C语言文件操作 1.1 fopen和fclose 1.2 fwrite和fread 1.3 C语言中的输入输出流 二、Linux的文件系统调用 2.1 open和文件描述符 2.2 close 2.3 read 2.4 write 三、Linux内核数据结构与文件描述符 一、C语言文件操作 在C语言中我们想要打开一个文件并对其进…

精进日常:每日练习与明智取舍的艺术

目录 题目1.对于非运行时异常&#xff0c;程序中一般可不做处理&#xff0c;由java虚拟机自动进行处理。2.下面哪个关键字可以用于Java的构造方法上&#xff1f;3.以下代码执行的结果显示是多少&#xff08; &#xff09;&#xff1f;注解总结 题目 选自牛客网 1.对于非运行时…

GCC编译:静态链接库与动态链接库

&#xff01; GCC 编译 C(C)静态链接库&#xff08;gcc -L、gcc -l&#xff09;和动态链接库&#xff08;gcc -fPIC -shared&#xff09;的创建和使用_fpic shared-CSDN博客https://blog.csdn.net/wohu1104/article/details/110789570静态链接库&#xff1a; 在 Linux 发行版…

JDFrame 一款比 Java 8 Stream 更灵活的数据处理工具

一、JDFrame 介绍 在大数据处理领域&#xff0c;Apache Spark以其强大的分布式计算能力和丰富的数据处理API而广受好评。然而&#xff0c;在许多日常的软件开发场景中&#xff0c;我们面临的数据量可能并不需要Spark这样的分布式系统来处理。相反&#xff0c;我们更希望有一种…

聊聊ChatGLM2-6B模型的微调

概述 GLM、ChatGLM的相关基础知识说明&#xff1a; GLM模型底层还是基于Transformer&#xff0c;因此其设计、优化都是围绕Transformer的各个组件的。从注意力层的掩码、位置编码等方面优化与设计。ChatGLM3/ChatGLM2的源码中&#xff0c;比如finetune、trainer等代码&#x…

看不见的硝烟:中国网络安全三十年沉浮史

昆仑侠 锦缎 2022 年 05 月 20 日 本文系基于公开资料撰写&#xff0c;仅作为信息交流之用&#xff0c;不构成任何投资建议。 2022 年 5 月 16 日&#xff0c;俄罗斯黑客组织 KillNet 向包括美国、英国、德国在内 10 个国家的政府正式 “宣战”。 2022 年 4 月 28 日&#xf…

vue如何在组件中监听路由参数的变化

使用 watch 监听 $route 对象 的变化&#xff0c;从而捕捉路由参数的变化 beforeRouteUpdate 导航守卫 当前组件路由更新时调用 beforeRouteUpdate 钩子只在组件被复用时调用&#xff0c;即当组件实例仍然存在时。如果组件是完全重新创建的&#xff0c;那么应该使用 beforeR…

GD 32 滤波算法

GD32硬件滤波算法 程序代码&#xff1a; #include <stdint.h> #include <stdio.h> #include "gd32f30x.h" #include "delay.h"static void GpioInit(void) {rcu_periph_clock_enable(RCU_GPIOC);gpio_init(GPIOC, GPIO_MODE_AIN, GPIO_OSPEED_…

log4j2远程执行代码CVE-2021-44228复现

一.访问网址 发现 /solr/admin/cores?action参数 可以上传 如下图 步骤二 在dnslog平台上来监控我们注入的效果 上传参数 solr/admin/cores?action${jndi:ldap://${sys:java.version}.jxmxiy.dnslog.cn 获得java版本号 查看他的回显 开始准备反弹shell 下载JDNI&#xff0c…

编程语言 | C | 代码整理 | 4月

八月拍了拍你&#xff0c;并对你说&#xff1a;“好运就要开始了”&#xff01; 目录 编程语言 | C | 代码整理 | 4月2019/4/12019/4/22019/4/22019/4/32019/4/42019/4/52019/4/62019/4/72019/4/82019/4/92019/4/102019/4/112019/4/122019/4/132019/4/142019/4/152019/4/162019…

【简历】武汉某985大学:前端简历指导,拿offer可能性低

注&#xff1a;为保证用户信息安全&#xff0c;姓名和学校等信息已经进行同层次变更&#xff0c;内容部分细节也进行了部分隐藏 简历说明 这是一份985武汉某大学25届的前端简历&#xff0c;那么985面向的肯定是大厂的层次&#xff0c;但是作为前端简历&#xff0c;学校部分&a…

Jenkins的安装方式

一、Jenkins是什么 Jenkins是一款开源CI&CD软件&#xff0c;用于自动化构建、测试和部署软件等各种任务&#xff0c;以实现持续集成。 Jenkins支持各种运行方式&#xff0c;可通过系统包、Docker或者通过一个独立的Java程序。 二、安装方式 2.1禅道智能应用平台一键安装…

区间预测 | 光伏出力的区间预测(Matlab)

区间预测 | 光伏出力的区间预测&#xff08;Matlab&#xff09; 目录 区间预测 | 光伏出力的区间预测&#xff08;Matlab&#xff09;效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.适用于matlab2020及以上。可任意选择置信区间&#xff0c;区间覆盖率picp、区间平均…

入门Pandas必练习100题基础到进阶|阶级教程2

作者:郭震 51. How to get the row number of the nth largest value in a column? Find the row position of the 5th largest value of column a in df. # input df pd.DataFrame(np.random.randint(1, 30, 30).reshape(10,-1), columnslist(abc)) df# Solution 1# argsort…

Modelsim仿真Vivado IP核报错

问题 VIVADO版本为2017.2&#xff0c;Modelsim版本为10.7c 在vivado中调用modelsim仿真&#xff0c;出现报错“Module GND is not defined.”&#xff0c;“Module LUT4 is not defined.”等等一大堆&#xff0c;所有的IP核都是这样的报错。 由于问题已经解决了所以我没有报…

基于Flask的出租车、GPS轨迹数据分析可视化系统

文章目录 有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主项目介绍技术路线内容介绍数据预处理系统界面可视化展示每文一语 有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主 项目介绍 针对杭州市出租车GPS数据的分析&…

万虹商城电影售票系统设计与实现

1 项目介绍 1.1 摘要 在如今高速发展的社会&#xff0c;电影产业蓬勃发展&#xff0c;人们对电影的需求日益增加&#xff0c;导致电影售票系统需要更加高效、便捷地满足观众的购票需求。传统的电影售票方式伴随着一系列的问题&#xff0c;排队购票现象是最为突出和普遍的现象…