面向对象编程,继承复制构造函数

时间:2010-01-15 09:35:07

标签: c++ oop

假设我有一个基类“人”。我公开地从基类“人”继承了一个班级“学生”。我还没有为base和派生类编写复制构造函数。现在假设我在主程序中写道

main()
{
student sobj1("name", "computer science");
student sobj2=sobj1;
}

现在在第二行中,将调用学生的默认编译器生成的复制构造函数,但在执行之前,将调用基类的默认复制构造函数,它创建一个匿名对象并初始化它然后控制返回到副本学生的构造函数,初始化学生的对象部分。
这是我们不写复制构造函数的情况的演示 现在假设我们为这两个类编写了复制构造函数,然后我在编写时测试了它

student sobj2=sobj1;

会发生什么,这行调用学生的复制构造函数,但是在这种情况下不会调用基类的复制构造函数(基类的默认构造函数将被调用)我的问题是为什么?

3 个答案:

答案 0 :(得分:4)

vava几乎有他的规则正确,这是一个更明确的版本:

  • 如果没有先构建基类子对象,就不能拥有派生类的实例:所有碱基'ctors首先执行。 ( Ctor 构造函数的简写。)
  • 如果没有首先构建该类的每个成员,就无法进入ctor的主体:所有成员的ctors在base'ctors 之后执行。
  • 编译器生成的默认ctor使用默认ctors 作为基础和成员。
  • 编译器生成的cctor执行成员复制:使用基础和成员的所有复制ctors。 ( Cctor 复制构造函数的简写。)
  • 编译器生成的赋值运算符执行成员分配:使用base和member的赋值运算符。 (赋值运算符也称为 operator = op = 。)
  • 当您自己实施ctor(任何ctor,包括复制ctor)时,任何没有初始化参数的基础或成员都将使用其默认ctor (在ctor初始化程序中,带有冒号的部分以及之前ctor的功能体。)。
  • 如果数据成员的默认ctor是微不足道的(或多或少“如果它是编译器生成的”)并且您没有在ctor初始化程序中指定该成员,那么该成员的值将是垃圾。
    • 这指出了这些规则仍然过于简化的原因;有关精致的详细信息,请参阅C ++标准中的12.6.2 / 3-4。
    • 这仅适用于具有普通默认ctors的数据成员。
    • 具有普通默认ctors的基类总是垃圾。

vava指定Person的copy ctor的例子是完全正确的:

struct Student : Person {
  Student(Student const& other) : Person(other) {}
};

最后一颗子弹的例子:

struct TrivialCtor { int n; };
struct A {
  TrivialCtor m;
  A() {}          // m.n is garbage
  A(int) : m() {} // m.n is 0

  friend ostream& operator<<(ostream& s, A const& v) {
    s << "m.n = " << v.m.n;
    return s;
  }
};

int main() {
  cout << "()   : " << A() << '\n';
  cout << "(int): " << A(42) << '\n';
  return 0;
}

答案 1 :(得分:3)

我相信规则如下:

  1. 基类的构造函数总是应该在派生类的构造函数之前调用。
  2. 您可以通过在初始化列表中显式调用它来选择将调用哪个基类构造函数。
  3. 如果不这样做,则调用默认构造函数。
  4. 当类没有复制构造函数时,编译器会生成一个复制构造函数。它将为类的所有成员调用默认构造函数基类的复制构造函数,就像你手写的构造函数实际上应该这样。
  5. 所以,你去吧。除非你调用基类的复制构造函数,否则将使用默认的BUT编译器足够聪明,可以在它自己生成的复制构造函数中实际调用它。

    以防您不知道如何调用它,例如

    Student(Student const & p): Person(p) {
    }
    

答案 2 :(得分:0)

罗杰和瓦瓦已经回答了你的技术问题。

但是,您现在可能没有意识到这一点,但您不希望支持从类的多态层次结构中复制对象。

首先,因为复制实体没有意义。复制学生的意义是什么?无!

其次,在将学生复制到一个人然后再回到学生身上时,你将不得不面对切片。而且你必须使用变通办法来支持任务 - Envelop-letter Idiom 是最知名的。

通过继承类似boost :: noncopyable(对于纯C ++ 98/03解决方案)这样的类来禁止基类中的复制和赋值,并通过指针处理实体。如果由于某些奇怪的原因你确实需要复制实体,请查看通常的clone()函数,该函数依赖于受保护的复制构造函数。