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

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 创建的函数对象会自动推导返回类型,无需显式指定
      绑定成员函数(常用)
cpp 复制代码
#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;
}

绑定函数

cpp 复制代码
#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;
}

绑定函数对象

cpp 复制代码
#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 的容器

事例代码

cpp 复制代码
#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可以显式的将一个左值转换为对应的右值引用类型

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

cpp 复制代码
#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函数

用法总结

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

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

cpp 复制代码
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禁止默认函数的做法

cpp 复制代码
class MyClass {
public:
    MyClass() = default;
    ~MyClass() = default;

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

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

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

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

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

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

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

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

constexpr

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

constexpr变量

  • 编译时求值的常量
  • constexpr确保在编译时进行求值,而const只可以确保值不能在运行中改变
cpp 复制代码
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中更改了)
cpp 复制代码
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确保表达式在编译时求值,并且变量在运行的时候是只读
cpp 复制代码
const int a = 10; // 运行时常量
constexpr int b = 10; // 编译时常量

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

初始化列表 initializer list

用法总结

  • 语法使用:直接初始化成员变量,而不用在构造函数体内赋值
  • 特点
    • 优化性能,减少性能开销
    • const成员变量必须通过初始化列表进行初始化,因为const成员变量在构造完成后不可以被赋值
    • 引用成员也必须通过初始化列表进行初始化
    • 顺序列表中的初始化的顺序必须和类中声明顺序一致
cpp 复制代码
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类型
  • 注意
    • **单一返回类型:**函数中所有返回语句必须是相同类型,否则编译器会报错
    • 返回引用和指针的时候,需要确保返回的对象在作用域中是否有效,避免悬空引用
cpp 复制代码
#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的使用情况自动推导参数的类型

事例案例理解

cpp 复制代码
#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;
}
cpp 复制代码
#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;
}
cpp 复制代码
#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;
}

变量模板

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

cpp 复制代码
#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;
}

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

cpp 复制代码
#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;
}

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

cpp 复制代码
#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;
}

类模版和变量模板

cpp 复制代码
#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属性

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

标记函数被弃用

cpp 复制代码
#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;
}

标记变量弃用

cpp 复制代码
#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;
}

标记类型弃用

cpp 复制代码
#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;
}

标记类的成员函数被弃用

cpp 复制代码
#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

cpp 复制代码
#include <iostream>
#include <memory>

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

创建动态数组

cpp 复制代码
#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;
}

创建自定义对象

cpp 复制代码
#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

结构化绑定

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

解构元组

cpp 复制代码
#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;
}

解构结构体

cpp 复制代码
#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;
}

解构数组

cpp 复制代码
#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;
}

与标准库结合使用

cpp 复制代码
#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语句范围内有用)

cpp 复制代码
#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语句范围内起作用

cpp 复制代码
#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表达式必须能够在编译的时候计算
cpp 复制代码
#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;
}

常量计算

cpp 复制代码
#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;
}

与标准库结合使用的场景

cpp 复制代码
#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嵌套

基于语法结构

cpp 复制代码
#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;
}
cpp 复制代码
#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())
cpp 复制代码
#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;
}
cpp 复制代码
#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;
}
cpp 复制代码
#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

总结

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

#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;
}
cpp 复制代码
#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则不支持传统的面向对象编程,但是提供结构体和特征来实现类似功能
相关推荐
西猫雷婶4 分钟前
python学opencv|读取图像(二十一)使用cv2.circle()绘制圆形进阶
开发语言·python·opencv
kiiila5 分钟前
【Qt】对象树(生命周期管理)和字符集(cout打印乱码问题)
开发语言·qt
小_太_阳30 分钟前
Scala_【2】变量和数据类型
开发语言·后端·scala·intellij-idea
直裾33 分钟前
scala借阅图书保存记录(三)
开发语言·后端·scala
唐 城1 小时前
curl 放弃对 Hyper Rust HTTP 后端的支持
开发语言·http·rust
码银3 小时前
【python】银行客户流失预测预处理部分,独热编码·标签编码·数据离散化处理·数据筛选·数据分割
开发语言·python
从善若水3 小时前
【2024】Merry Christmas!一起用Rust绘制一颗圣诞树吧
开发语言·后端·rust
lqqjuly3 小时前
特殊的“Undefined Reference xxx“编译错误
c语言·c++
冰红茶兑滴水3 小时前
云备份项目--工具类编写
linux·c++
刘好念4 小时前
[OpenGL]使用 Compute Shader 实现矩阵点乘
c++·计算机图形学·opengl·glsl