2

我有一个关于复制构造函数的问题。我在互联网上看到了这些例子。第一个说没有复制构造函数,如果您在 student2 上更改某些内容,相同的字段也会在 student1 上更改。但是在第二个示例中,由于复制构造函数,student2 上的更改不会影响 student1。我不明白这是怎么发生的,实际上复制构造函数在这里做什么?(抱歉英语不好)(感谢所有答案:))

class MITStudent {
public:
    int studentID;
    char *name;
    MITStudent() {
        studentID = 0;
        name = "";
}

};
   int main() {
      MITStudent student1;
      student1.studentID = 98;
      char n[] = "foo";
      student1.name = n;
      MITStudent student2 = student1;
      student2.name[0] = 'b';
      cout << student1.name; // boo
 }

第二个

class MITStudent {
public:
    int studentID;
    char *name;
    MITStudent() {
        studentID = 0;
        name = "";
    }

    MITStudent(MITStudent &o) {
        name = my_strdup(o.name);
        studentID = o.studentID;
    }

};
int main() {
   MITStudent student1;
   student1.studentID = 98;
   char n[] = "foo";
   student1.name = n;
   MITStudent student2 = student1;
   student2.name[0] = 'b';
   cout << student1.name; // foo

}

4

5 回答 5

3

如果您不指定自己的,则会自动生成默认的复制构造函数。
他们只是按值将所有类的成员复制到新类。

当您将指针作为类成员时,通常会出现问题。
默认的复制构造函数只会复制指针所持有的地址。
这意味着原始类和复制类现在都指向同一个对象。

这正是您使用char*“字符串”的示例中发生的情况......

顺便说一句,作为一个经验法则..如果您有一个具有指针作为成员的类,请创建一个自定义复制构造函数。

于 2012-07-28T15:57:26.557 回答
0

在典型情况下,使用默认的复制构造函数,情况将如左图所示!. 实现了复制构造函数来避免这种情况,并具有右侧给出的场景。

然而,这通常发生在指针成员身上。所以,尽量避免它们。仅在以下情况下使用它们 1. 只能在构造函数之后的阶段创建成员 2. 想要销毁成员并重新创建它 3. 想要使成员比对象更长寿。

就您而言,您似乎不在上述任何情况下。在这种情况下,您可以安全地使用漂亮的字符串对象,而不必担心任何悬空指针。

于 2012-07-28T16:14:33.570 回答
0

如果您不创建一个复制构造函数,则会自动为您生成一个。自动生成的复制构造函数只会将指针复制到名称而不是名称本身。通过创建自己的构造函数,您可以手动复制整个名称,而不仅仅是指针。

在实际代码中,您可能希望使用 std::string 之类的东西而不是 char* 。这样,自动生成的复制构造函数就会做你想做的事,而你不需要自己编写。

于 2012-07-28T15:54:02.803 回答
0

如果没有MITStudent(MITStudent &o),则只是复制所有字段的值。因此,如果有一个指针字段,那么两个字段将包含相同的地址。

于 2012-07-28T15:57:34.560 回答
0

在第一个示例中,复制构造函数由编译器隐式创建。

它基本上看起来像这样:

MITStudent(const MITStudent &o) {
    name = o.name;
    studentID = o.studentID;
}

它只复制指针name

在第二个示例中,复制构造函数被显式创建并复制name指向的数据。这样,nameinstudent2就是指向复制的数据。

于 2012-07-28T15:58:14.787 回答