[Lang] 构造与析构
[Lang] 构造和析构
1. 深拷贝与浅拷贝
- 浅拷贝是在复制对象时,仅复制对象的成员变量的值,而不考虑这些成员变量是否指向了动态分配的内存或其他资源。也就是说,浅拷贝只复制指针的值,不复制指针所指向的内容。编译器默认提供的拷贝构造函数是浅拷贝。
- 深拷贝是在复制对象时,不仅复制对象的成员变量的值,而且会复制指针所指向的内存或资源。这意味着每个对象拥有自己的独立副本,不会共享内存或资源。
当类涉及动态内存分配时,必须使用深拷贝,避免悬空指针问题。
#include<iostream>
#include<cstring>
using namespace std;
class MyString
{
private:
char *str;
public:
// 无参构造
MyString()
{
str = nullptr;
cout << "无参构造" << endl;
}
// 有参构造
MyString(const char *s)
{
str = new char[strlen(s) + 1];
strcpy(str, s);
cout << "有参构造" << endl;
}
// 拷贝构造
MyString(const MyString &s)
{
str = new char[strlen(s.str) + 1];
strcpy(str, s.str);
cout << "拷贝构造" << endl;
}
// 析构函数
~MyString()
{
if (str != nullptr) delete[] str;
cout << "析构函数" << endl;
}
void set(const char *s)
{
if (str != nullptr) delete[] str;
str = new char[strlen(s) + 1];
strcpy(str, s);
}
void print()
{
cout << str << endl;
}
};
int main()
{
MyString s1;
MyString s2("hello, world!");
MyString s3(s2);
s1.set("Hello, World!");
s1.print();
s2.print();
s3.print();
return 0;
}
[Running] cd "d:\CppDev\Lang\constructor\" && g++ test1.cpp -o test1 && "d:\CppDev\Lang\constructor\"test1
无参构造
有参构造
拷贝构造
Hello, World!
hello, world!
hello, world!
析构函数
析构函数
析构函数
[Done] exited with code=0 in 1.121 seconds
2. 构造与析构的顺序
- 构造:当创建一个对象时,首先调用构造函数。对于基类和派生类,基类的构造函数先被调用,然后是派生类的构造函数。
- 析构:当对象被销毁时,首先调用派生类的析构函数,然后是基类的析构函数。这保证了派生类中使用的资源可以先被正确释放。
#include<iostream>
using namespace std;
class ParentClass
{
public:
ParentClass()
{
cout<<"父类构造函数"<<endl;
}
~ParentClass()
{
cout<<"父类析构函数"<<endl;
}
};
class ChildClass : public ParentClass
{
public:
ChildClass()
{
cout<<"子类构造函数"<<endl;
}
~ChildClass()
{
cout<<"子类析构函数"<<endl;
}
};
int main()
{
ChildClass obj;
return 0;
}
[Running] cd "d:\CppDev\Lang\constructor\" && g++ test2.cpp -o test2 && "d:\CppDev\Lang\constructor\"test2
父类构造函数
子类构造函数
子类析构函数
父类析构函数
[Done] exited with code=0 in 0.917 seconds
3. malloc/free与new/delete区别
- 构造和析构:
malloc
/free
只负责内存的分配和释放,而不涉及对象的构造和析构。new
/delete
则同时负责内存内存管理和构造析构。 - 类型安全:
new
是类型安全的,它返回正确类型的指针,不需要进行强制类型转换。而malloc
返回void*
指针,需要显式转换类型。 - 错误处理:
malloc
在分配失败时返回NULL
,而new
在分配失败时会抛出std::bad_alloc
异常。