构造析构是 C++ 对象生命周期的核心。对象什么时候出生、资源什么时候拿到、什么时候释放、复制时是深拷贝还是浅拷贝,这些都直接影响稳定性和安全性。

4.4 默认构造函数

默认构造函数用于创建对象时不传参数。

1
2
3
4
5
6
7
class Buffer {
public:
Buffer() : size(0) {}

private:
int size;
};

4.5 带参构造函数

带参构造可以在对象创建时建立有效状态。

1
2
3
4
5
6
7
class User {
public:
explicit User(int id) : id(id) {}

private:
int id;
};

explicit 可以避免一些隐式转换带来的误用。

4.6 拷贝构造函数

拷贝构造在用一个对象初始化另一个对象时触发。如果类里有堆资源,默认浅拷贝可能出问题。

1
2
3
4
5
6
7
8
9
class Person {
public:
Person(const Person &other) {
age = other.age;
}

private:
int age = 0;
};

4.7 构造函数重载

同一个类可以有多个构造函数,根据参数不同建立对象。

4.8 委托构造函数

一个构造函数可以委托给另一个构造函数,减少重复初始化逻辑。

1
2
3
4
5
6
7
8
9
class Point {
public:
Point() : Point(0, 0) {}
Point(int x, int y) : x(x), y(y) {}

private:
int x;
int y;
};

4.9 初始化列表

初始化列表比在构造函数体里赋值更早发生。const 成员、引用成员、没有默认构造函数的成员必须用初始化列表。

5.0 构造默认参数

构造函数也可以有默认参数,但不要让多个构造函数产生二义性。

5.1 构造函数删除

= delete 可以禁用某些构造或拷贝行为。

1
2
3
4
5
class FileHandle {
public:
FileHandle(const FileHandle &) = delete;
FileHandle &operator=(const FileHandle &) = delete;
};

5.2 析构函数机制

析构函数在对象生命周期结束时自动调用,用来释放资源。

1
2
3
4
5
6
7
8
class Resource {
public:
Resource() { data = new int[10]; }
~Resource() { delete[] data; }

private:
int *data = nullptr;
};

5.3 构造析构顺序

构造顺序通常是:基类 → 成员对象 → 当前类构造函数体。析构顺序相反。局部对象离开作用域时自动析构。

5.4 析构出场时机

对象类型 析构时机
局部对象 离开作用域
堆对象 delete
全局对象 程序结束时
静态局部对象 程序结束时

5.5 浅拷贝与深拷贝

浅拷贝只复制指针值,两个对象会指向同一块资源;深拷贝会复制资源内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <cstring>

class Text {
public:
explicit Text(const char *s) {
size = std::strlen(s);
data = new char[size + 1];
std::strcpy(data, s);
}

Text(const Text &other) {
size = other.size;
data = new char[size + 1];
std::strcpy(data, other.data);
}

~Text() {
delete[] data;
}

private:
char *data = nullptr;
size_t size = 0;
};

复盘重点:只要类管理资源,就要考虑拷贝构造、赋值运算和析构。

5.6 静态成员变量

静态成员属于类,不属于某个对象。它在所有对象之间共享。

5.7 静态成员函数

静态成员函数没有 this 指针,只能直接访问静态成员。

5.8 常量成员变量

const 成员必须在初始化列表中初始化。

5.9 常量成员函数

const 成员函数承诺不修改对象状态。

1
2
3
int value() const {
return count;
}

6.0 常量对象特性

常量对象只能调用常量成员函数。这样能保证只读对象不被修改。

6.1 对象调用规则

普通对象调用成员函数时会隐式传入 this 指针。const 对象的 this 类型不同,所以只能调用 const 成员函数。

6.2 对象指针本质

对象指针保存对象首地址。成员变量通过偏移访问,成员函数通过代码地址调用。

6.3 对象指针特性

对象指针要关注空指针、生命周期和真实动态类型。继承多态后,基类指针可能指向派生类对象。

6.4 类的友元函数

友元函数可以访问类的私有成员,但会破坏封装边界。只在确实需要时使用。

6.5 友元函数与类

友元类会获得更大访问权限,项目中要谨慎使用,避免对象内部状态被随意修改。

本章复盘模板

项目 问题
构造 对象创建后是否处于有效状态
析构 资源是否一定释放
拷贝 是浅拷贝还是深拷贝
静态成员 是否引入共享状态
常量函数 只读接口是否标记 const
友元 是否真的需要突破封装

学习检查清单

检查项 状态
能说明构造函数和析构函数的调用时机 待复盘
能解释深拷贝和浅拷贝的区别 待复盘
能写出初始化列表 待复盘
能说明静态成员和普通成员的区别 待复盘
能理解 const 成员函数和常量对象的关系 待复盘