C/C++基础之二(类的构造函数)
Talk is cheap. Show me the code.
1. 构造函数,有参,无参?
2. 析构函数的调用时机?
3. 如何在构造函数中初始化某个成员类?
4. 拷贝构造函数的凶残?
5. 操作符重载的奇妙设计!
1 |
|
- 输出如下
1 | Person() |
我们写了一些属性以及get/set方法,当这个类交给一个工具类的时候他想做一些操作,因为属性一般是private的,因此他必须要调用get,set方法,那么就出现了一种叫做firend的函数,可以直接访问私有属性,上代码:
1 |
|
然后上面的程序似乎没有问题,但是其实是有问题的。这个问题来自于类的拷贝:
1️⃣ 浅拷贝的定义
浅拷贝就是 直接拷贝对象的所有成员,包括指针 只拷贝指针本身的值(地址),而不拷贝指针指向的内容。
例如:
class Demo {
public:
int* ptr;
Demo(int val) { ptr = new int(val); }
~Demo() { delete ptr; }
};
int main() {
Demo d1(5);
Demo d2 = d1; // 默认拷贝构造函数执行 → 浅拷贝
}
d2.ptr 和 d1.ptr 指向同一块堆内存
当 d1 析构时释放了内存 → d2.ptr 悬空
再析构 d2 → double free / 崩溃
✅ 这就是浅拷贝的典型问题。
2️⃣ 什么时候会触发浅拷贝
(1) 按值传递对象
void foo(Demo d) { … } // d 是按值传递
Demo obj(5);
foo(obj); // 触发拷贝构造(默认浅拷贝)
函数内部会调用 拷贝构造函数
默认拷贝构造函数就是浅拷贝
(2) 返回对象(按值返回)
Demo createDemo() {
Demo d(10);
return d; // 触发拷贝构造(默认浅拷贝)
}
编译器通常会做 返回值优化(RVO) 避免拷贝,但如果没有 RVO,也会发生浅拷贝
(3) 对象赋值
Demo d1(5);
Demo d2(10);
d2 = d1; // 默认赋值运算符 → 浅拷贝
这里 d2 的原 ptr 被覆盖
如果原 ptr 已经分配了内存,可能造成内存泄漏
同时 d1 和 d2 共享同一块内存 → double-free
3️⃣ 浅拷贝的问题
悬空指针:多个对象指向同一块动态分配内存
double-free:析构函数释放同一块内存两次
内存泄漏:赋值时忘记释放旧的资源
4️⃣ 解决方法
深拷贝(deep copy):在拷贝构造和赋值运算符中,重新分配内存并复制内容
使用智能指针或 std::string:自动管理内存,避免浅拷贝问题
下面看看我们的例子,使用深拷贝构造函数&‘=’运算符重写,解决这个棘手的问题:
1 |
|
输出结果
1 | Point() |