C++学习--------------类与对象(复制构造函数)

浅拷贝

          二进制复制不复制指向的内存单元,这导致两个 MyString 对象指向同一个内存单元。函数 UseMyString( )返回时,变量 str 不再在作用域内,因此被销毁。为此,将调用 MyString 类的析构函数, 而该析构函数使用 delete[]释放分配给 buffer 的内存,这将导致 main( ) 中的对象 sayHello 指向的内存无效,而等 main( )执行完毕时,sayHello 将不再在作用域内,进而被销 毁。但这次不再有有效的内存地址调用 delete(销毁 str 时释放了该内存,导致它无效)。正是 这种重复调用 delete 导致了程序崩溃。

eg:

//Mystring 类声明

 class MyString
 {
 private:
 char* buffer;        //指针成员

 public:
 MyString(const char* initString) // constructor
 {
 buffer = NULL;
 cout << "Default constructor: creating new MyString" << endl;
 if(initString != NULL)
 {
 buffer = new char [strlen(initString) + 1];
 strcpy(buffer, initString);

 cout << "buffer points to: 0x" << hex;
 cout << (unsigned int*)buffer << endl;
 }
 }

//以Mystring类值做参数
//编译器以二进制复制指针buffer
//这时新创建的对象 str.buffer 与 main函数中Mystring类对象的buffer指针指向同一片
//内存空间,当函数结束,析构函数销毁buffer指向的内存,main 中的对象当程序结束释放
//时,指向的空间已经销毁,导致出错。
 void UseMyString(MyString str)
 {
 cout << "String buffer in MyString is " << str.GetLength();
 cout << " characters long" << endl;

 cout << "buffer contains: " << str.GetString() << endl;
 return;
 } 

深拷贝

使用复制构造函数确保深复制

复制构造函数是一个重载的构造函数,由编写类的程序员提供。每当对象被复制时,编译器都将 调用复制构造函数。 为 MyString 类声明复制构造函数的语法如下:

class MyString
{
 MyString(const MyString& copySource); // copy constructor
};
MyString::MyString(const MyString& copySource)
{
 // Copy constructor implementation code
} 

 定义一个复制构造函数,确保对动态分配的缓冲区进行深复制

class MyString
{
private:
   char* buffer;

public:
   MyString() {}
   MyString(const char* initString) // constructor
   {
      buffer = NULL;
      cout << "Default constructor: creating new MyString" << endl;
      if(initString != NULL)
      {
         buffer = new char [strlen(initString) + 1];
         strcpy(buffer, initString);

         cout << "buffer points to: 0x" << hex;
         cout << (unsigned int*)buffer << endl;
      }
   }

   MyString(const MyString& copySource) // Copy constructor
   {
      buffer = NULL;
     cout << "Copy constructor: copying from MyString" << endl;
      if(copySource.buffer != NULL)
      {
         // allocate own buffer 
         buffer = new char [strlen(copySource.buffer) + 1];

         // deep copy from the source into local buffer
         strcpy(buffer, copySource.buffer);

         cout << "buffer points to: 0x" << hex;
         cout << (unsigned int*)buffer << endl;
      }
   }

   MyString operator+ (const MyString& addThis) 
   {
      MyString newString;

      if (addThis.buffer != NULL)
      {
         newString.buffer = new char[GetLength() + strlen(addThis.buffer) + 1];
         strcpy(newString.buffer, buffer);
         strcat(newString.buffer, addThis.buffer);
      }

      return newString;
   }

   // Destructor
   ~MyString()
   {
      cout << "Invoking destructor, clearing up" << endl;
      delete [] buffer;
   }

   int GetLength() 
   { return strlen(buffer); }

   const char* GetString()
   { return buffer; }
};

void UseMyString(MyString str)
{
   cout << "String buffer in MyString is " << str.GetLength();
   cout << " characters long" << endl;

   cout << "buffer contains: " << str.GetString() << endl;
   return;
}

int main()
{
   MyString sayHello("Hello from String Class");
   UseMyString(sayHello);

   return 0;
}

 

输出结果说明,buffer指向的空间不同,这样析构函数释放空间不会再出错

复制构造函数确保下面的函数调用进行深复制:

MyString sayHello("Hello from String Class");
UseMyString(sayHello); 

然而,如果通过赋值进行复制时,结果如何呢?

MyString overwrite("who cares? "); 
overwrite = sayHello;

由于没有提供复制赋值运算符 operator=,编译器提供的默认复制赋值运算符将导致浅复制。

内容参考:

《21天学通C++》(第八版)[美] Siddhartha Rao 著 袁国忠 译

猜你喜欢

转载自blog.csdn.net/qq_30386541/article/details/82888493