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

[C++11] 类中新特性的添加

默认的移动构造和移动赋值

在 C++11 之前,编译器会为每个类自动生成默认的构造函数、析构函数、拷贝构造函数、拷贝赋值运算符等函数,以实现对象的创建、销毁和拷贝操作。但拷贝操作会复制整个对象的数据,效率低,尤其是在处理大对象或动态分配的资源时。为了解决这一问题,C++11 引入了移动语义(Move Semantics),并提供了两个新的默认函数:移动构造函数移动赋值运算符

移动构造和移动赋值运算符的作用是通过“转移”资源来代替“复制”资源,提高效率。它们通常用于避免不必要的拷贝操作,尤其是当资源的原有所有者不再需要保留这些资源时。

生成规则

  • 若类未定义析构函数、拷贝构造函数、拷贝赋值运算符或移动构造函数,编译器会自动生成默认的移动构造和移动赋值运算符。
  • 若类包含自定义析构函数、拷贝构造函数或拷贝赋值运算符,则编译器不会自动生成移动构造和移动赋值运算符,除非显式指定 =default

移动构造函数和移动赋值的行为

  • 内置类型成员将按字节逐一拷贝。
  • 自定义类型成员会优先调用它们的移动构造函数(若存在),否则调用拷贝构造函数。

也就是说,与其他的默认函数一样,自定义类型仍然需要看本身有没有实现相应的函数。

示例代码
#include <string>
#include <utility> // 包含std::moveclass Person {
public:Person(const char* name = "", int age = 0): _name(name), _age(age) {}// 移动构造函数自动生成,因为未定义拷贝构造或赋值函数private:std::string _name;int _age;
};int main() {Person p1("Alice", 25);Person p2 = std::move(p1); // 触发移动构造return 0;
}

在上述代码中,std::movep1 转换为右值引用(rvalue reference),指示编译器可以“转移”p1 的资源,而无需拷贝。p1 的数据会被移动到 p2,此操作避免了 p1 的拷贝过程。

注意

若类定义了移动构造函数或移动赋值运算符,编译器不会再自动生成拷贝构造函数和拷贝赋值运算符。

声明时给缺省值

在 C++11 之前,默认参数值只能在函数声明中给出,不能直接在成员变量定义时赋值。而 C++11 允许在类的成员变量声明时直接赋默认值,这一特性提高了代码的简洁性,并增强了初始化的灵活性。这样,在构造对象时,若未传入对应参数,成员变量会自动采用声明时指定的默认值。

示例代码

class Person {
public:Person(const char* name = "") : _name(name) {}private:std::string _name = "DefaultName"; // 直接在声明中赋缺省值int _age = 18; // 默认值为 18
};int main() {Person p; // _name 初始化为 "DefaultName",_age 初始化为 18return 0;
}

通过在声明时赋值,减少了构造函数中初始化的代码量,避免重复设置默认值,提高了可读性。

defaultdelete

C++11 引入了 =default=delete,提供更精细的控制:

  • =default:当类中定义了某个自定义函数(如拷贝构造),编译器不会自动生成移动构造函数。若希望保留自动生成的行为,可使用 =default 显式要求编译器生成该函数。
  • =delete:通过 =delete,可以禁用类的某些默认行为(如拷贝或赋值),例如禁用拷贝构造可以避免误用拷贝构造函数带来的资源分配问题。

示例代码:

class Person {
public:
Person(const char* name = "", int age = 0)
: _name(name), _age(age) {}Person(const Person& p) = delete; // 禁用拷贝构造函数
Person(Person&& p) = default;      // 显式要求生成默认移动构造函数private:
std::string _name;
int _age;
};int main() {Person s1("Alice", 25);// Person s2 = s1; // 错误:拷贝构造函数被禁用Person s3 = std::move(s1); // 调用默认的移动构造函数return 0;
}

finaloverride

在 C++ 的继承和多态中,派生类可能会误写或错写基类的虚函数,导致未按预期覆盖基类的行为。C++11 提供了 finaloverride 关键字,帮助开发者更好地控制和检测继承链中的函数覆盖行为。

  • override:用于修饰派生类中的虚函数,表示这是对基类中同名虚函数的覆盖。如果函数签名不匹配,编译器会报错。
  • final:用于修饰类或虚函数,表示该类或虚函数不允许被进一步继承或重写。
示例代码
class Base {
public:virtual void display() const {std::cout << "Base class display" << std::endl;}virtual void show() const final { // 不允许派生类重写此函数std::cout << "Base class show" << std::endl;}
};class Derived : public Base {
public:void display() const override { // 正确覆盖基类的displaystd::cout << "Derived class display" << std::endl;}// void show() const override; // 错误:不能重写final函数
};// class FurtherDerived : public Derived final {}; // 不允许进一步派生

override 关键字帮助避免虚函数重写错误,final 关键字则能阻止类或函数的进一步派生和重写,提升代码安全性和可读性。


http://www.mrgr.cn/news/69873.html

相关文章:

  • 第三十一篇——微分(下):搞懂“奇点”,理解“连续性”
  • 【Flume实操】实时监听 NetCat 端口和本地文件数据到 HDFS 案例分析
  • 第11课 string类型的应用
  • 工单系统在手,双重挑战无忧
  • 用 Python 从零开始创建神经网络(三):添加层级(Adding Layers)
  • 【图】图学习
  • 了解Hadoop:大数据处理的核心框架
  • JUC并发队列及应用
  • 计算机研究生方向,零基础入门到精通,收藏这篇就够了
  • halcon仿射变换核心技术分析
  • 2024年【危险化学品生产单位主要负责人】找解析及危险化学品生产单位主要负责人考试技巧
  • 910. 最小差值 II
  • 《Python网络安全项目实战》项目3 处理文件中的数据_练习题(2)
  • GB/T 43206—2023信息安全技术信息系统密码应用测评要求(二)
  • 闭包的知识
  • CMS那点事
  • 分布式唯一ID生成(二): leaf
  • 网站架构知识之Ansible进阶(day022)
  • JavaScript深拷贝与浅拷贝:区别及实现方法详解
  • 【计算机架构】什么是 ROM