构造多态类

Construction of polymorphic classes

本文关键字:多态      更新时间:2023-10-16

我有一个关于使用继承构造类的方式的问题。在下面的例子中,对Base构造函数的调用依赖于Derived类中实现的函数。这个函数再次依赖于Derived成员generator,直到Base构造函数调用之后才初始化。

如果先构造Base类,变量Base::in_不会包含垃圾数据吗?

class Derived
    : public Base
{
    Derived()
        : Base(get_data()),
          generator(5) {}
    Generator generator;
    int get_data() { return generator.get_some_data(); }
};
class Base
{
    Base(int in)
         : in_(in) {}
    int in_;
}

首先,代码中没有任何东西是多态的。多态性是关于虚函数的。

接下来,您的 Base不依赖于任何东西。看看class Base {和匹配的}之间,没有任何东西依赖于外部的任何东西。 Derived中的Base 子对象的构造依赖于派生类的另一个成员,该成员在Base之后构造。你的分析基本上是正确的,这是一个真正的问题,需要通过重构你的类来解决。 最简单的方法是Base的两阶段初始化(以下是伪代码,可能无法编译):
class Base {
    Base(int in = 0) : in_(in) {}
    void set(int in) { in_ = in; }
    int in_;
};
class Derived : public Base {    
    Derived() : Base(), generator(5) {
      Base::set(generator);
    }
    ...
};

另一个方法是将依赖项移动到另一个基类:

class Base2 { ... generator implemented here ... };
class Derived : public Base2, public Base {
  Derived() : Base2(5), Base(Base2::generator) {}
};

参见继承中调用构造函数/析构函数的顺序

在初始化派生类的任何成员之前,将调用Base的构造函数。因此,当调用get_data()时,生成器将不会被初始化。

基本上,Base将使用垃圾初始化

我不知道标准是怎么说的,但这显然是一个问题,当get_data()被调用时,generator的值是什么,就像你从其他地方调用它一样,然后构造函数。

从构造函数内部调用的代码与其他代码没有任何不同。
我的猜测是get_data()在生成器构造之前被调用,因此您将在运行时获得NULL异常。

另一点要提到的是,基类当然是首先构造的。它是基类。Derived是一个Base,它有一个字段in_
根据经验,一个好的模式是:

  1. 避免从构造函数调用方法。使用一个额外的init方法。
  2. 无论如何都要小心循环构造函数调用。

你也可以在Base中使get_data抽象,然后在BaseInit()中调用它,这在我看来是实现对子类依赖的正确方式。

class Derived
    : public Base
{
    Derived()
        : Base(),
          generator(5) {}
    Generator generator;
    virtual int get_data() { return generator.get_some_data(); }
};
class Base
{
    Base()
    {
    }
    Init() {
       in_ = get_data();}   
    int in_;
    virtual int get_data() = 0;
}