拷贝构造函数的深浅拷贝详解
- 默认拷贝构造函数可以完成对象的数据成员值简单的复制。
- 对象的数据资源是有指针指示的堆时,默认拷贝构造函数仅作指针值复制。
而浅拷贝,在某些情况下,例如,当类的数据成员中有指针类型时,就会带来数据安全方面的隐患,
我们就需要定义一个特定的拷贝构造函数,该拷贝构造函数不仅可以实现原对象和新对象之间数据成员
的拷贝,而且可以为新的对象分配单独的内存资源,这就是 深拷贝构造函数。
自定义拷贝构造函数,进行深拷贝,即,各对象有各自的内存空间。
#include <iostream>
using namespace std;
class String
{
public:
String(const char *str = NULL)
{
if(str == NULL)
{
m_data = new char[1]; //虽然传过来是空字符串,但也要存放'\0';
*m_data = '\0';// 把m_data指向的内存空间 置为空('\0')
}
else
{
length = strlen(str);
m_data = new char[length+1]; //字符串有个"\0",所以长度要加1
strcpy(m_data,str);//把str指向的内存空间内容 拷贝 到m_data指向内存空间
}
cout << "我是构造函数" << endl;
}
//自定义拷贝构造函数,
String(const String& other)
{
length = strlen(other.m_data);
m_data = new char[length+1];
strcpy(m_data,other.m_data);
cout << "我是拷贝构造函数" << endl;
}
String& operator=(const String &other)
{
//先判断传进的参数和当前实例(*this)是不是同一个实例
if (this == &other)
{
return *this;
}
delete []m_data;//释放原有的内存资源,防止内存泄露
length = strlen(other.m_data);
m_data = new char[length+1];
strcpy(m_data,other.m_data);
return *this;
}
~String()
{
if (m_data != NULL)
{
delete []m_data;//这里,析构对象tr2和tr1时候,共释放了两次,因此程序崩溃
m_data = NULL; //把指针置为NULL
length = 0;
}
cout << "我是析构函数" << endl;
}
private:
char* m_data;
int length;
};
void objmain()
{
String tr1("abcdef");
String tr2 = tr1; //此时会调用默认拷贝构造函数,但是C++编译器提供的是浅拷贝,因此在释放内存时候,释放了两次,所以程序崩溃
String tr3("ABCDEF");
tr3 = tr1;//C++编译器提供的等号操作也属浅拷贝
//tr3.operator=(tr1); 相当于这样调用
}
int main()
{
objmain();
system("pause");
return 0;
}看看 内存剖析图
构造函数的初始化列表
C++中提供初始化列表对成员变量进行初始化
语法规则:
Constructor::Contructor() : m1(v1), m2(v1,v2), m3(v3)
{
// some other assignment operation
}
注意:成员变量的初始化顺序只与声明的顺序相关,与在初始化列表中的顺序无关
具体调用顺序,先执行 类对象 的构造函数,如果 类对象有多个,按照声明顺序执行,
而不是按照初始化列表的顺序。 析构函数与构造函数执行顺序相反。
New delete 和 malloc free 的联系和区别
相同点:都是在堆上进行动态的内存操作。
不同点: new 和delete 是运算符,不是函数,因此执行效率高。
而malloc 和free 是函数,并且用malloc函数需要指定内存分配的字节数,且不能
初始化对象。
new会自动调用对象的构造函数,delete会自动调用对象的析构函数。
用new分配数组空间时,不能指定初值。如果由于内存不足等原因而无法正常分配空间。
则new会返回一个空指针(NULL),用户可以根据该指针的值判断分配空间是否成功。
C++中的静态成员变量和静态成员函数
static关键字的作用:
- 函数体内的static变量的作用范围为该函数体,该变量的内存只被分配一次
- 在模块内的static的全局变量可以被模块内的所有函数调用,但不能被模块外其他函数访问。
- 类中的static成员变量属于整个类所拥有,对类的所有对象只有一份拷贝。
- 在模块内的static函数只可被该模块内的其他函数调用。
- 类中的static成员函数属于整个类所拥有,这个函数不接受this指针,因而只能访问类的static成员变量。
C++面向对象模型:
语言中直接支持面向对象程序设计的部分,主要涉及如构造函数,析构函数,虚函数,继承
(单继承,多继承,虚继承,多态)等等。
对于各种支持的底层实现机制。
概况的说,在C++类中有两种成员变量:静态成员变量,和非静态成员变量;三种成员函数:
静态成员函数,非静态成员函数,虚函数。 如图:
C++类对象中的成员变量和成员函数时分开存储的。
成员变量:
普通成员变量:存储在对象中,与Struct变量有相同的内存布局和字节对齐方式
静态成员变量:存储于全局数据区。
成员函数:存储在代码段中。
由上图可以看出:
C++中类的普通成员函数都隐式包含一个指向当前对象的this指针。
而静态成员函数不包含指向具体对象的this指针。
本文深入解析了C++中拷贝构造函数的原理,重点对比了浅拷贝与深拷贝的区别及应用场景。通过自定义拷贝构造函数实现了深拷贝,确保了数据安全和资源的有效管理。
840

被折叠的 条评论
为什么被折叠?



