当前位置: 首页 > article >正文

常用的关键特性

目录

一、字面量。

二、静态断言。

三、构造函数分类。

1,构造函数。

2,析构函数。

四、default和delete。

五、override和final。

六、constexpr。


作为一种广泛使用的编程语言,C++具有无可争议的强大的功能性和灵活性。从系统编程到游戏开发,从嵌入式到上位机,C++无处不在。随着版本的不断演进,新的特性被引入。以下列举探讨一些开发中常用的关键特性。

一、字面量。

字面量是程序中直接表示固定值的表达式,具有很强的语义清晰度。C++ 支持多种类型的字面量,如整数字面量、浮点字面量、字符字面量、字符串字面量和布尔字面量。使用合适的字面量可以提高代码的可读性和维护性。

编译阶段的处理

在 C++ 的编译阶段,字面量被视为常量表达式,编译器将其直接嵌入生成的机器代码中。这种处理方式使得字面量的使用非常高效,因为它们不需要在运行时动态分配内存。例如,整数字面量 10 在编译时会被直接替换为其值,不会产生额外的内存开销。

编译器在解析字面量时会根据其类型进行适当的处理和类型推导。例如,浮点字面量可能会被处理为 floatdouble,具体取决于字面量的格式(如 3.14f 表示 float)。对于字符串字面量,编译器会生成相应的字符数组,并在内部处理其存储和生命周期。

#include <iostream>

int main() {
    int a = 10;                // 整数字面量
    double b = 3.14;          // 浮点字面量
    char c = 'A';             // 字符字面量
    const char* str = "Hello"; // 字符串字面量

    std::cout << a << " " << b << " " << c << " " << str << std::endl;
    return 0;
}

常用场景

在项目中,字面量常用于配置常量和替代魔法数字。使用命名常量(如 const int MAX_USERS = 100;)替代字面量,不仅提高了代码的可读性,还减少了出错的几率。此外,确保使用合适的数据类型(如 intfloat)可以避免由于隐式转换导致的精度问题。

二、静态断言。

静态断言是编译时检查某个条件的工具,特别适用于模板编程。在编写泛型代码时,确保类型的有效性是至关重要的。

在进行底层库和框架开发时,静态断言通常用于确保模板参数的有效性。通过在模板中使用静态断言,可以在编译时提供清晰的错误信息,减少运行时错误的可能性。为了提高代码的可维护性,建议在静态断言中提供清晰且具体的错误信息。

#include <iostream>
#include <type_traits>

template <typename T>
void check() {
    static_assert(std::is_integral<T>::value, "T must be an integral type");
}

int main() {
    check<int>();    // 编译通过
    // check<double>(); // 编译错误
    return 0;
}

三、构造函数分类。

C++ 中的成员函数可以根据需要进行多种类型的修饰,包括构造函数、析构函数、拷贝构造函数、移动构造函数等。

1,构造函数。

构造函数是用于初始化类对象的特殊成员函数。C++ 支持多种类型的构造函数:

默认构造函数

无参数的构造函数,用于创建对象时赋予默认值。

class MyClass {
public:
    MyClass() {
        // 默认构造函数
    }
};

参数化构造函数

带参数的构造函数,用于根据给定值初始化对象。

class MyClass {
public:
    MyClass(int x) {
        // 参数化构造函数
    }
};

拷贝构造函数

用于通过另一个同类对象初始化新对象。

class MyClass {
public:
    MyClass(const MyClass& other) {
        // 拷贝构造函数
    }
};

移动构造函数(C++11 及以后)

用于通过右值引用移动资源。

class MyClass {
public:
    MyClass(MyClass&& other) noexcept {
        // 移动构造函数
    }
};

2,析构函数。

析构函数在对象生命周期结束时调用,用于释放资源。每个类只能有一个析构函数。

class MyClass {
public:
    ~MyClass() {
        // 析构函数
    }
};
  • 默认构造函数:在需要创建对象时,无需提供初始值的情况下使用,适合类有合理的默认状态时。

  • 参数化构造函数:在对象创建时根据特定值初始化,适合需要定制化初始状态的情况。

  • 拷贝构造函数:在需要深拷贝对象的情况下使用,确保源对象和目标对象各自拥有独立的资源,避免潜在的资源共享问题。

  • 移动构造函数:在性能敏感的情况下使用,特别是涉及动态内存分配时,可以避免不必要的深拷贝,提升性能。

#include <iostream>
#include <vector>

class MyClass {
public:
    MyClass() {
        std::cout << "Default constructor called." << std::endl;
    }

    MyClass(int x) {
        std::cout << "Parameterized constructor called with value: " << x << std::endl;
    }

    MyClass(const MyClass& other) {
        std::cout << "Copy constructor called." << std::endl;
    }

    MyClass(MyClass&& other) noexcept {
        std::cout << "Move constructor called." << std::endl;
    }

    ~MyClass() {
        std::cout << "Destructor called." << std::endl;
    }
};

int main() {
    MyClass obj1;              // 调用默认构造函数
    MyClass obj2(42);          // 调用参数化构造函数
    MyClass obj3 = obj2;       // 调用拷贝构造函数
    MyClass obj4 = std::move(obj2); // 调用移动构造函数

    return 0;
}

四、default和delete。

C++11 引入了 default delete 关键字,以便于更精确地控制构造函数、赋值运算符和析构函数的生成或禁止。这些特性在对资源管理的使用场景中尤为重要。

在处理资源管理(如内存、文件句柄等)时,使用 delete 禁止拷贝构造和赋值是最佳实践。这确保了资源的独占性,避免了潜在的双重释放或内存泄漏问题。而 default 可以用于简单类的默认行为生成,保持代码简洁和可读。

class MyClass {
public:
    MyClass() = default;      // 默认构造函数
    MyClass(const MyClass&) = delete; // 禁止拷贝构造
    MyClass& operator=(const MyClass&) = delete; // 禁止拷贝赋值
};

int main() {
    MyClass obj1; // 可以创建对象
    // MyClass obj2 = obj1; // 编译错误
    return 0;
}

五、override和final。

overridefinal 关键字在多态编程中应用较多,可用于控制虚函数的重写和继承,帮助我们更清晰地表达意图,通过前期编译检查,避免潜在错误。

在设计类层次结构时,建议使用 override 来标识重写的方法。这不仅有助于代码的可读性,还能在基类方法签名发生变化时,及时捕获错误。此外,使用 final 可以防止不必要的重写,从而增强接口的稳定性。

class Base {
public:
    virtual void show() {
        std::cout << "Base show" << std::endl;
    }
    virtual void print() final {
        std::cout << "Base print" << std::endl;
    }
};

class Derived : public Base {
public:
    void show() override {
        std::cout << "Derived show" << std::endl;
    }
    // void print() override { } // 编译错误
};

int main() {
    Derived d;
    d.show(); // Derived show
    d.print(); // Base print
    return 0;
}

六、constexpr。

constexpr 关键字使得函数和变量可以在编译时求值,有助于在常量表达式中提升性能。这一特性对于性能敏感的应用场景尤为重要。 在模板编程和常量表达式求值的场景中,constexpr 的使用可以显著提升运行时性能。要注意,constexpr 函数的实现必须符合特定要求,如所有参数必须为常量表达式,并且不能包含运行时决定的控制流。     

#include <iostream>

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

int main() {
    constexpr int result = factorial(5);
    std::cout << "Factorial of 5 is: " << result << std::endl; // 120
    return 0;
}

  


http://www.kler.cn/a/373762.html

相关文章:

  • Vue 3:解析
  • 【Linq】在C#中从SQL query case语句发布到linq扩展方法
  • wsl 使用docker 部署oracle11g数据库
  • 代码随想录-字符串-反转字符串中的单词
  • 2024年,Rust开发语言,现在怎么样了?
  • Redis有什么不一样?
  • 心觉:抄袭是一种智慧
  • SM单元 硬件
  • 力扣227:基本计算器II
  • Java语言的Springboot框架+云快充协议1.5+充电桩系统+新能源汽车充电桩系统
  • 派生类重载的delete操作符调用时可以动态绑定吗
  • 创建一个基于SSM框架的药品商超管理系统
  • springboot响应文件流文件给浏览器+前端下载
  • redis详细教程(3.hash和set类型)
  • [TypeError]: type ‘AbstractProvider‘ is not subscriptable
  • 三项智能网联汽车强制性国家标准正式发布(附图解)
  • 应用在汽车控制系统安全气囊的爱普生可编程晶振SG-8018CG
  • SpringBoot技术:闲一品交易的新机遇
  • Java 多线程(九)—— JUC 常见组件 与 线程安全的集合类
  • ComfyUI正式版来袭!一键安装无需手动部署!支持所有电脑系统
  • 线程本地变量-ThreadLocal
  • CMake知识点
  • [LeetCode] 36. 有效的数独
  • JAVA的动态代理
  • 创新实践:基于边缘智能+扣子的智能取物机器人解决方案
  • DDRPHY数字IC后端设计实现系列专题之后端设计导入,IO Ring设计