• 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

  • 相关阅读:
    SuperMap房产测绘成果管理平台
    SuperMap产权登记管理平台
    Android adb shell am 的用法(1)
    由浅入深谈Perl中的排序
    Android 内存监测和分析工具
    Android 网络通信
    adb server is out of date. killing...
    引导页使用ViewPager遇到OutofMemoryError的解决方案
    adb logcat 详解
    How to send mail by java mail in Android uiautomator testing?
  • 原文地址:https://www.cnblogs.com/yinhaichao/p/3042303.html
Copyright © 2020-2023  润新知