C++中一般创建对象,拷贝或赋值的方式有构造函数,拷贝构造函数,赋值函数这三种方法。下面就详细比较下三者之间的区别以及它们的具体实现。
1. 构造函数
构造函数有哪些特点:
a.构造函数的命名必须和类的命名相同。
b.如果一个类中没有定义构造函数的话,编译器会默认添加构造函数,该构造函数为无参构造。
c.构造函数完成类的成员变量的初始化和对象的内存的申请。类成员变量初始化有两种方式:1、可以在类内定义的时候通过初始化列表的情况下进行初始化。2、可以通过在类外定义构造函数内完成初始化。
d. 构造函数可以实现重载,可以带一个或多个参数,析构函数则不能被重载,只能定义一个。
class Animal
{
public:
int m_color; //颜色
Animal(); //无参构造函数
Animal(int type); //带参构造函数
virtual ~Animal(); //析构函数,未定义的情况下编译器会添加默认析构函数
void Eat(void)
{
cout << "Aninal Eat" << endl;
}
};
另外说明一下:
一个C++的空类,编译器会加入哪些默认的成员函数:
默认构造函数和拷贝构造函数
析构函数
赋值函数(赋值运算符)
取值函数
**即使程序没定义任何成员,编译器也会插入以上的函数!
2. 拷贝构造函数
构造函数的特点:
a.拷贝构造函数可以理解为一种特殊的构造函数,函数名和类名相同,参数为为类的引用。
b.拷贝构造应用在对没有初始化的对象用已经存在的对象进行初始化操作。
c.在类内未定义的情况下,编译器也会添加默认拷贝构造函数。
在C++中,3种对象需要复制,此时拷贝构造函数会被调用
- 一个对象以值传递的方式传入函数体
- 一个对象以值传递的方式从函数返回
- 一个对象需要通过另一个对象进行初始化
例如:
Animal dog1; //调用构造函数
Animal dog2(dog1);//调用拷贝构造函数
Animal dog2=dog1; //调用拷贝构造函数
注:因为系统提供的默认拷贝构造函数工作方式是浅拷贝。如果对象中用到了需要手动释放的对象,则会出现问题,这时就要手动重载拷贝构造函数,实现深拷贝。
下面说说深拷贝与浅拷贝:
- 浅拷贝:如果复制的对象中引用了一个外部内容(例如分配在堆上的数据),那么在复制这个对象的时候,让新旧两个对象指向同一个外部内容,就是浅拷贝。(指针虽然复制了,但所指向的空间内容并没有复制,而是由两个对象共用,两个对象不独立,删除空间存在)
- 深拷贝:如果在复制这个对象的时候为新对象制作了外部对象的独立复制,就是深拷贝。
关于浅拷贝和深拷贝可以参考博客:https://blog.csdn.net/caoshangpa/article/details/79226270
拷贝构造函数的定义:
class Animal
{
public:
int m_color; //颜色
Animal();
Animal(int type);
Animal(const Animal& Ani) //拷贝构造函数
{
cout << "拷贝构造" << endl;
}
}
3. 赋值函数
赋值函数的特点:
a.赋值函数是对“=”赋值操作符的重载,可以通过赋值的形式对两外一个对象的成员进行者赋值。
b.一个对象对另一个对象赋值时,两个对象都是已经初始化过的。
代码示例如下:
Animal& operator=(const Animal& Ani) //赋值运算符重载
{
if (this != &Ani)
{
m_color = Ani.m_color;
m_life = Ani.m_life;
}
return *this;
}
拷贝构造和赋值函数的区别:
1)拷贝构造函数是一个对象初始化一块内存区域,这块内存就是新对象的内存区,而赋值函数是对于一个已经被初始化的对象来进行赋值操作。
2)一般来说在数据成员包含指针对象的时候,需要考虑两种不同的处理需求:一种是复制指针对象,另一种是引用指针对象。拷贝构造函数大多数情况下是复制,而赋值函数是引用对象
3)实现不一样。拷贝构造函数首先是一个构造函数,它调用时候是通过参数的对象初始化产生一个对象。赋值函数则是把一个新的对象赋值给一个原有的对象,所以如果原来的对象中有内存分配要先把内存释放掉,而且还要检察一下两个对象是不是同一个对象,如果是,不做任何操作,直接返回。
拷贝构造和赋值函数的应用:
Animal dog1; //调用构造函数
Animal dog2=dog1; //调用拷贝构造函数,此处dog2对象不存在
Animal dog3;
dog3 = dog2; //调用赋值重载函数
注:本博客参考了:https://www.jb51.net/article/158473.htm