前言:对于类的一些构造之前有一定的了解,但到具体的技术细节,总会有些纰漏,经过多方查阅,有了一些新的感悟,在这里做一个总结,方便之后翻阅。
首先声明一个简单类型MyClass,做测试用:
#include <stdio.h>
#include <iostream>
using namespace std;
class MyClass
{
private:
int i; //实例对象,用于模拟类信息
int *p; //实例指针对象,用于模拟类信息
public:
static int count; //静态变量,用于统计实际产生多少个对象
MyClass(int i)
{
cout << "Enter MyClass Creater:" << this << endl;
count++; //每生成一个对象,统计count就+1
p = new int;
this->i = i;
}
~MyClass()
{
cout << "Enter MyClass Deleter:" << this << endl;
count--; //每销毁一个对象,统计count就-1
if (NULL != p)
{
delete p;
}
}
MyClass(const MyClass& myObject)
{
cout << "Enter MyClass Coper:" << this << endl;
this->i = myObject.i;
count++; //复制对象时,统计数+1
p = new int;
*p = *(myObject.p);
}
MyClass & operator=(const MyClass& myObject)
{
cout << "Enter MyClass Assigner:" << this << endl;
this->i = myObject.i; //对象赋值时,统计数不需要变动
return *this;
}
};
int MyClass::count = 0;
一、当对象通过形参传入其他函数中时(按照注释的顺序):
MyClass fun01(MyClass myObject) //2)myObject作为形参传入,调用复制构造函数,count=2
{
return myObject; //3)return返回时会cope到一个临时变量,进入复制构造函数,count=3,之后因为fun01的myobject在栈上,会调用调用此处的myobject的析构函数,所以count--之后,count=2
}
int main()
{
MyClass myObject(1); //1)count=1
MyClass myObject2 = fun01(myObject); //4)此处没有对象接收函数返回值时,会调用临时变量的析构函数,count=1,
return 0;
}//5)此处析构掉栈上的对象main的myObject,count=0
可以想象,当对象参数通过引用的方式传入的时候,由于不会复制对象,所以count最大值只会到2。
二、复制构造函数与赋值构造函数
int main()
{
MyClass myObject1(1);
MyClass myObject2=myObject1; //对象myObject2本身不存在,调用复制构造函数,最后是两个对象
MyClass myObject3(1);
MyClass myObject4(2);
myObject4 = myObject3; //对象myObject4本身存在,调用赋值构造函数,最后是两个对象
return 0;
}
另外,通过对象初始化的话也是调用复制构造函数(MyClass myObjectx(myObject4))。
三、为什么要重写复制构造函数
class MyClass2
{
private:
int i; //实例对象,用于模拟类信息
int *p; //实例指针对象,用于模拟类信息
public:
static int count; //静态变量,用于统计实际产生多少个对象
MyClass2(int i)
{
cout << "Enter MyClass2 Creater:" << this << endl;
count++; //每生成一个对象,统计count就+1
p = new int;
this->i = i;
}
~MyClass2()
{
cout << "Enter MyClass2 Deleter:" << this << endl;
count--; //每销毁一个对象,统计count就-1
if (NULL != p)
{
delete p;
}
}
};
int MyClass2::count = 0;
int main()
{
MyClass2 myObject5(1);
MyClass2 myObject6 = myObject5; //对象myObject6本身不存在,调用默认复制构造函数,最后是一个对象
return 0;
}
编译器会默认生成复制构造函数,但是默认生成的复制构造函数是的按位复制对象(浅复制),并不会生产新的对象(myObject6就是myObject5)。当对象内部含有指针对象(MyClass2的p),造成复制出来的的对象内部的指针类型数据(myObject6->p)和原本对象内部的指针类型数据(myObject5->p)值一致,导致所指向的目标一致(*myObject6->p和*myObject5->p),结果导致第一个对象delete之后,第二个对象重复delete。
另外,默认复制构造函数导致MyClass2::count并不会增加。
所以我们需要创建自定义的复制构造函数进行深复制(参看MyClass)。
之后若有其他关于对象结构的内容,会在此处补充。