C ++ Copy构造函数和运算符

时间:2015-06-04 17:54:47

标签: c++ class pointers operators copy-constructor

我试图了解Copy constructorOperator。我读了一些代码,但我还没有得到它。

这是主要功能

int main()
{
Cwin win1('A',"window")
Cwin win2;
win1 = win2;
win1.set_data('B',"hello");
win1.show();
win2.show();
}

我从 Class Cwin

中提取最重要的代码
Class Cwin
{
  private:
  char id, *title ;

  public:
  Cwin(char i, char *text){......} //constructor
  Cwin(){......}  //default constructor, id ='D' , *title = "default"
  Cwin(const Cwin &win)
  {
    id = win.id;
    strcpy(title,win.title);
  }
  ......
};

输出

B : hello
B : hello

我能理解是什么原因造成的。但是我无法理解以下修复它的解决方案。

Class Cwin 
{
   private:
   char id, *title ;

   public:
   Cwin(char i, char *text){......} //constructor
   Cwin(){......}  //default constructor, id ='D' , *title = "default"
   Cwin(const Cwin &win)
   {
     id = win.id;
     strcpy(title,win.title);
    }

   void operator=(const Cwin &win)
   {
     id = win.id;      
     strcpy (this->title , win.title);
   }
   ......


 };

输出:

B : hello
D : default

为什么将strcpy (title , win.title);更改为strcpy (this->title , win.title);会产生巨大影响?

3 个答案:

答案 0 :(得分:3)

说明:

在成员函数内部,您可以编写this->titletitle。两者都是等价的,除非你有一个名为title的本地函数变量,然后该名称将隐藏该成员。

WHat的不同之处在于您添加了一个assignement运算符。

如果没有assignement运算符,您的语句win1 = win2会按成员复制成员继续。在这种情况下,指针会按原样复制,因此在复制后,两个对象都将指向相同的指向char*

enter image description here

当您set_data()后,字符串将被char*复制到win1指针,但win2指向相同的值。

您的第二个代码段更好地处理副本:指向的字符串的内容被复制/复制到另一个对象指向的char*。因此,win1win2将继续使用2个不同的字符串。

备注/建议

  • 您使用strcpy()而不检查目标是否足够长以包含复制的字符串。这可能会导致缓冲区溢出,内存损坏以及许多其他可怕的事情。

  • 我强烈建议您尽可能使用std::string代替char*:默认副本管理得很好,而且您不会使用>>> l = [100,55,104,400] >>> sortedl = sorted(l) >>> [sortedl.index(i) for i in l] [1, 0, 2, 3] 。 t必须关心内存分配/释放,长度。

答案 1 :(得分:2)

如果Cwin没有显式实现自己的赋值运算符(第一个示例没有),编译器将生成一个默认实现,它只是将成员值从一个对象复制到另一个对象。这就是为什么你的输出对两个对象说同样的事情 - 使用默认的assigment-operator实现的win1 = win2语句只是用指针值win1.title覆盖了win2.title的指针值,并且因此,两个title成员都指向同一个内存块,后续的win1.set_data()语句填充了数据。

要执行您的要求,您应该将title更改为使用std::string而不是char*,让它为您处理复制。它可以与编译器的默认复制构造函数和赋值运算符实现一起使用(除非你有其他数据需要手动复制):

#include <string>

Class Cwin
{
private:
  char id;
  std::string title;

public:
  Cwin()
    : id('D'), title("default") {}

  Cwin(char i, const std::string &text)
    : id(i), title(text) {}

  void set_data(char i, const std::string &text)
  {
    id = i;
    title = text;
  }

  void show()
  {
    std::cout << id << " : " << title << std::endl;
  }
};

但是,如果您需要直接使用char*,则必须正确实现copy-constructor和assignment-operator,以确保正确复制title数据,例如:

#include <cstring> 

Class Cwin
{
private:
  char id, *title ;

public:
  Cwin()
    : id(0), title(NULL)
  {
    set_data('D', "default");
  }

  Cwin(char i, char *text)
    : id(0), title(NULL)
  {
    set_data(i, text);
  }

  Cwin(const Cwin &win)
    : id(0), title(NULL)
  {
    set_data(win.id, win.title);
  }

  ~Cwin()
  {
    delete[] title;
  }

  Cwin& operator=(const Cwin &win)
  {
    if (this != &win)
      set_data(win.id, win.title);
    return *this;
  }

  void set_data(char i, char *text)
  {
    int len = std::strlen(text);
    char *newtitle = new char[len+1];
    std::strcpy(newtitle, text);

    delete[] title;
    title = newtitle;
    id = i;
  }

  void show()
  {
    std::cout << id << " : " << title << std::endl;
  }
};

每当你必须在构造函数中手动分配内存并在析构函数中释放它时,你也需要在copy-constructor和assignment-operator中复制那些数据。阅读The rule of three/five/zero。在这种情况下,CWin需要遵循三条规则以便与char*一起正常运行,但可以遵循零规则使用std::string。您应该尽可能地努力编写遵循零规则的代码,这样可以更容易管理。

答案 2 :(得分:2)

C ++类有一个默认的赋值运算符,只要你将该类的一个成员赋给其他成员,除非你重载它,否则它会执行shallow copy。 (初始化时除外,它使用复制构造函数)

现在,在第一部分中找到你的代码没有赋值运算符的重载,因此它所做的是将win2元素的浅层副本复制到win1,而win1又复制了&#39; id&#39 ;和标题&#39;指针(不是指向它的字符串(存储))。 主要功能如下:

int main()
{
  Cwin win1('A',"window")
  /*
    This will create a new object win1
    win1.id = 'A' and win1.title will point to "window"
  */
  Cwin win2;
  /*
    This will create a new object win2
    win2.id = 'D' and win2.title will point to "default"
  */

  win1 = win2;
  /*
  This will do somewhat the following
  win1.id = win2.id;
  win1.title = win2.title; ( note that  the pointer is copied )
  Now , win1.id = 'D' win2.id = 'D'
  win1.title points "Defalult"
  win2.title points "Default"
  */

  win1.set_data('B',"hello");
  /*
  This sets the win.id = 'B'
  and now the win1.title points to "hello"
  Also since win1.title and win2.title are both the same pointer
  so win2.title will also point to  "hello"
  */
  win1.show();
  win2.show();
}

但是在第二部分中你重载了赋值运算符,它不是复制指针而是复制它所指向的字符串(存储)。现在主要运行如下:

int main()
{
  Cwin win1('A',"window")
  /*
    This will create a new object win1
    win1.id = 'A' and win1.title will point to "window"
  */
  Cwin win2;
  /*
    This will create a new object win2
    win2.id = 'D' and win2.title will point to "default"
  */

  win1 = win2;
  /*
  This will now do what is in the overloaded assignment operator
  where to copy the string strcpy is used which will copy the content
  of the string instead of copying the pointers
  Now , win1.id = 'D' win2.id = 'D'
  win1.title points "Defalult"
  win2.title points "Default"
  */

  win1.set_data('B',"hello");
  /*
  This sets the win.id = 'B'
  and now the win1.title points to "hello"
  win2.title will still point to  "Default"
  */
  win1.show();
  win2.show();
}

因此,给定的结果。 您还必须查看并遵循此answer中给出的建议。