c++的构造函数和析构方面(拷贝构造函数)

头文件
class  student
{
public:
 student(char*);
 ~student();
 student(const student &);
 char* name;
 static int num;
};

 main.cpp文件

int  student::num=0;

student::student(char* myname)

{

num++;

int len=strlen(myname);

name=new char[len+1];

strcpy(name,myname);

cout<<name<<":创建,剩余个数:"<<num<<endl;

}

student::~student()

{

num--;

cout<<name<<":销毁,剩余个数:"<<num<<endl;

delete [] name;

}

void fun(student  funs)

{

cout<<funs.name<<"被调用"<<endl;

}
void main()

{

student stu1("student1");//--------------1

student stu2("student2");//--------------2

student stu3("student3");//--------------3

 

fun(stu2);//--------------4

student stu4=stu3;//--------------5

student stu5("student5");//--------------6

stu5=stu1;//--------------7

}

123都很正常,到4的时候,实参为类值对象,传递过程是一个拷贝构造函数,funs在fun方法结束后会调用析构函数,而运行到5的时候,这是一个通过拷贝构造函数实例化类,这个过程不会调用构造方法和析构函数的,因为我们要了解拷贝构造函数是如何写的,如下
student(const student & c)

{

name=c.name;

}

所以5就相当于 student stu4(stu3)

7的时候只是赋值,不是通过拷贝构造函数实例化类,因为stu5已经在6的时候实例化了

这个代码在VC 6.0中运行的时候,神奇般的出错了,第一个错误出在main函数结束后,一个个析构,堆栈的析构顺序是先进后出,先析构stu5,再析构stu4,再析构stu3,就在析构stu3的时候出错了。截图如下


为什么会出错,此时研究后发现是因为在5这个位置调用了拷贝构造函数来构造stu4类对象,根据拷贝构造函数的原型(下是原型)
student(const student & c)

{

name=c.name;

}


我发现name=c.name,对于5来说就是stu4.name=stu3.name;name是一个指针,这是一个指针赋值,即stu4name指针指向了stu3的那么指针指向的位置。那么问题迎刃而解了,即在析构stu4的时候(因为堆栈析构顺序先析构晚压入栈的),delete [] name了,就是告诉计算机,name这块内存被释放了,不被任何东西指向(不和任何东西有关系),于是再去析构stu3的时候,出问题了。。你已经和这块地址没有关系了,凭什么让你delete。而且也没必要delete了,但是如果你知道这块空间地址,并通过地址直接访问这块空间还是能访问到name的值的,因为值并没有被删除,修改代码后,你会更加明白问题在哪里,在56之间加上一句:cout<<"stu3name指向地址:"<<(int *)stu3.name<<"\t"<<"stu4name指向地址:"<<(int *)stu4.name<<endl;
输出(您可以不要直接cout<<"stu3name指向地址:"<<&stu3.name<<"\t"<<"stu4name指向地址:"<<&stu4.name<<endl;这样来访问,这是获取该指针在堆栈中的地址,而不是内容在堆中存储的地址)

要解决这个问题。。看样子只有重写拷贝构造函数了(下面是重构拷贝构造函数)

student::student(const student& tempstu)

{

int len=strlen(tempstu.name);

name=new char[len+1];

strcpy(name,tempstu.name);

}
以为一切问题解决,可是运行的时候

很明显这是在析构1的时候,即析构stu1的时候,发现第7stu5=stu1;这只是一个赋值过程,因为stu5对象在第6句就构造了,赋值的过程的话,即依然是stu5.name=stu1.name,然后问题原因道理同上。这就是所谓的浅复制的过程,这也是浅复制容易导致的问题(大家可以去研究浅复制和深复制)

至于结构中的最后 的剩余个数为什么编程-2了,(其实这个例子模仿c++ primer),主要是因为位置4调用了fun(stu2);-这个调用,传递了一个实参为stu2的类对象,在传递过程类似
student  funs=stu2;这个funs对象在fun方法返回时会销毁,销毁就会调用析构函数num--,而且在第5位置处,是通过student stu4=stu3这种拷贝构造函数来实例化stu4,在重写的拷贝构造函数中,我们并没有让num++,而析构他的时候却有num--了,这就是为什么最后num不会回归至初始0,而是-2

原文地址:https://www.cnblogs.com/yinhaichao/p/3042303.html