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

xiaoxiao2021-02-28  124

        在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。三个对象均有独立的变量空间,而不是上面的三个指针指向同一个变量。所以,当一个类的数据成员为指针并且深拷贝很重要的时候,一般的做法就是自己实现三大函数,
转载请注明原文地址: https://www.6miu.com/read-33002.html

最新回复(0)