• 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

  • 相关阅读:
    Electron踩坑记录
    TypeScript实现设计模式——生成器模式
    在express中使用ES7装饰器构建路由
    微信小程序下载文件(非图片),并校验扩展名。
    防抖与节流
    yarn
    spark
    docker php-fpm中安装GD库
    thinkphp6 多应用路由遇坑记
    CentOS 7 开启SSH远程登录
  • 原文地址:https://www.cnblogs.com/yinhaichao/p/3042303.html
Copyright © 2020-2023  润新知