析构函数、复制构造函数,operator=以及深拷贝浅拷贝问题

来源:互联网 发布:plc和单片机哪个工资高 编辑:程序博客网 时间:2024/06/08 07:10

        在C++中,伴随类的有三个已经写好的特殊函数,它们是析构函数、复制构造函数和operator=。在许多情况下,都可以采用编译器提供的默认操作,有些时候却不行。

    1,析构函数

        析构函数是每个类中必要的函数,一般不需要单独定义,在类形成的时候会自动定义。当一个对象超出其作用域或者执行delete时,就调用析构函数。通常,析构函数的作用是释放使用对象时占用的所有资源,这其中包括每一个相应的new调用delete,以及关闭所有打开的文件等。默认操作是对每一个成员变量都使用析构函数。析构函数的固定形式是~ClassName();。

    2,复制构造函数

        在我们定义类的对象的时候,一般都会用到复制构造函数,复制构造函数一般可以通过下面三种方式调用(例如Test对象):
  • 声明的时候初始化,例如 Test B = A; Test B( A ); 而不是 B = A;。
  • 使用按值调用传递(而不是通过&或constant &)的对象无论如何都应该减少使用。
  • 通过值(而不是通过&或const &)返回对象。
        第一种情况比较常见,后面的两种都会构造用户看不到的临时对象。
默认情况下,复制构造函数操作的对象是类中每一个成员变量,简单数据类型(int、char或指针 )的变量,直接赋值就好,对于本身又是类对象的数据成员,它本身的复制构造函数又会作用于其每一个数据成员。

    3,operator=

        当=作用于两个已经构造的函数时,调用复制赋值运算符operator=。它的默认情况跟复制构造函数一样,也是作用于每一个数据成员。

    4,浅拷贝( shallow copy),深拷贝(deep copy)

        一般情况下,类的数据成员是由基本数据类型(int、double、vector<int>、string甚至是vector<string>)构成时三大函数的默认值都是适用的,但当类中存在数据成员是指针,而且这个指针指向一个动态分配地址的对象时,,默认的析构函数不会对指针进行任何操作(一个很好的理由就是释放这个指针就必须删除自身)。而且,复制构造函数和operator=都不复制指针指向的对象,而是简单的复制指针的值,这样的话,就会导致所有的指针都指向同一个对象,这被称为浅拷贝,而我们一般期望的是深拷贝。
下面代码展示了一个浅拷贝的示例:
#include <iostream>using namespace std;class Test{public:    explicit Test(int initValue = 0)    {        storedValue = new int (initValue);    }    int read() const    {        return *storedValue;    }    void write(int x)    {        *storedValue = x;    }private:    int * storedValue; //数据成员是指针,默认值不能用};int main(){    Test a(2);    Test b = a;    Test c;    c = b;    a.write(3);    cout << a.read() << endl << b.read() << endl << c.read() << endl;    return 0;}
上述代码逻辑上只有a为3,但实际上输出了3个3,问题就在于默认的operator=和复制构造函数都只是复制指针storedValue,导致三个对象的指针storedValue均指向了同一个int型变量,这些复制都是浅复制。下述代码通过三大函数来解决这个问题。
#include <iostream>using namespace std;class Test{public:    explicit Test( int initValue = 0 );    Test( const Test & rhs ); //复制拷贝函数    ~Test(); //析构函数    const Test & operator = ( const Test & rhs ); //operator=    int read();    void write( int x );private:    int * storedValue; //数据成员是指针,默认值不能用};Test::Test(int initValue){    storedValue = new int( initValue );}Test::Test( const Test & rhs){    storedValue = new int( *rhs.storedValue );}Test::~Test(){    delete storedValue;}const Test & Test::operator=( const Test & rhs){    if( this != &rhs) //判断 = 两侧是否是同一对象        *storedValue = *rhs.storedValue;    return *this;}int Test::read(){    return *storedValue;}void Test::write(int x){    *storedValue = x;}int main(){    Test a(2);    Test b = a;    Test c;    c = b;    a.write(3);    cout << a.read() << endl << b.read() << endl << c.read() << endl;    return 0;}
上面的输出结果是3,2,2。三个对象均有独立的变量空间,而不是上面的三个指针指向同一个变量。所以,当一个类的数据成员为指针并且深拷贝很重要的时候,一般的做法就是自己实现三大函数,


阅读全文
0 0
原创粉丝点击