01 - 类介绍,构造与析构
以 C 语言对面向对象能力的局限性引出 C++ 的类,简要介绍后提了下类的构造函数和析构函数。
面向对象与面向过程
面向对象和面向过程是一个相对的概念:
- 面向过程是按照计算机的工作逻辑来编码的方式,最典型的面向过程的语言是 c 语言,它直接对应汇编,汇编又对应电路。
- 面向对象则是按照人类的思维来编码的一种方式,C++ 就完全支持面向对象功能,可以按照人类的思维来处理问题。
举个例子,要把大象装冰箱,按照人类的思路自然是分三步,打开冰箱,将大象装进去,关上冰箱。
按照面向对象的思想(用 cpp),需要有人和冰箱两个对象,人能给冰箱发指令,冰箱可以接受指令并打开 / 关闭冰箱门:
class Fridge { public: void openDoor() {}; void closeDoor() {}; }; class Person { public: void openFridge(const Fridge& fridge) {}; };
按照面向过程的思想(用 C),只能定义人和冰箱的结构体,然后再来三个函数,执行三步动作:
struct Person {}; struct Fridge {}; void PersonOpenFridge(const Person& person, const Fridge& fridge); void PersonCloseFridge(const Person& person, const Fridge& fridge);
如果动作变多了,那代码量就大大增加,而且很乱。从开发者的角度讲,面向对象显然更利于程序设计。
因此,在 Cpp 中引入了类。
类的构造函数
类相当于定义了一个新类型,该类型生成在堆或栈上的对象时内存排布和 c 语言相同。但是 c++ 规定,C++ 有在类对象创建时就在对应内存将数据初始化的能力,这就是构造函数。
普通构造函数
可以通过构造函数初始化器来写一个普通构造函数:
class Test { public: Test(int i1_, int i2_) :i1(i1_), i2(i2_) {} private: int i1; int i2; };
复制构造函数
也称为 拷贝构造函数 (Copy Constructor),用另一个对象来初始化对象对应的内存。
可以使用构造函数初始化器来写:
class Test { public: Test(const Test& test): i1(test.i1), i2(test.i2) {} private: int i1; int i2; };
如果没有自己写复制构造函数,编译器会自动生成一个,因此在多数情况 (而不是所有情况) 下,不需要亲自编写复制构造函数。
这个构造函数使用 const 引用 作为参数,这样可以避免对源对象的复制和修改,提高性能。
移动构造函数
也是用另一个对象来初始化对象,单开了一篇文章具体讨论。
默认构造函数
当类没有任何构造函数时,编译器会为该类生成一个默认的构造函数,在最普通的类中,默认构造函数什么都没做,对象对应的内存没有被初始化。
类的析构函数
当类对象被销毁时,就会调用析构函数。栈上对象的销毁时机就是函数栈销毁时,销毁顺序和声明并构建的顺序相反;堆上的对象销毁时机就是该堆内存被手动释放时,如果用 new 申请的这块堆内存,那调用 delete 销毁这块内存时就会调用析构函数(后面应该用智能指针)。
class Test { public: ~Test() {} }
如果没有声明它,编译器会自动生成一个,会逐一销毁成员,然后允许释放对象。
参考资料
- 飘零的落花 - 现代 C++ 详解
- C++20 高级编程