C ++继承基础构造函数,但仍调用默认派生构造函数

时间:2017-05-10 13:48:22

标签: c++ c++14

我一直在努力解决这个问题:

目前我有这段代码:

class B {
  public:
    B(int, int, int, int);
    [many other ctors]
};

class D : public B {
  public:
    using B::B;
    [other methode]
};

现在我希望D管理一些指针,我需要独立于传递给构造函数的参数进行初始化。

我试过这个:

class B {
  public:
    B(int, int, int, int) {
      [other stuff]
      init();
    }
    [many other ctors]
    virtual void init() {}
};

class D : public B {
  public:
    using B::B;
    void init() {
      mPointer = new Stuff(42);
    }

  private:
    mPointer = nullptr;
};

但显然如果从B :: B(int,int,int,int)调用虚方法,则调用B :: init,而不是D :: init。

有没有一种很好的方法来完成这项工作,还是我需要在D中重新编写所有B&C的ctors?

谢谢!

3 个答案:

答案 0 :(得分:2)

您无法从构造函数中调用虚函数。这与对象的构造顺序有关:

struct E {
    E() { std::cout << "E" << std::endl; }
    int g = 7;
};

struct F : E {
    B() { std::cout << "F" << g << std::endl; }
};

F f;

构建f时,程序将输出EF7。首先构造基类,因此在派生类中,您可以调用方法并使用父级的成员。

事实上,通过上面的简单示例,您可以在g构造函数中使用变量F,因为之前调用了父构造函数。否则会形成错误,因为E的构造函数是g7

的设置

这与你的问题有什么关系?

好吧,在基础构造函数中,您正在调用虚函数。您希望调用的虚函数在派生类中调度。问题是,它还没有派生类。

你看,首先构建了类B。现在还没有D!由于尚未存在D,因此无法调用D函数进行虚拟调度!因此,编译器将回退到当时可以选择的函数。在您的情况下,该函数是B init函数。

答案 1 :(得分:1)

正如其他人所说,在构造函数中调用派生的虚函数并不是一件容易的事,但它并不是解决问题的唯一方法。

在您特定的情况下,我理解为您希望初始化继承类的成员但仍然重用基类构造函数,您可以使用类内成员初始化。这有效:

#include <string>
#include <iostream>

class Base {
  public:
    Base(int, int, int) { std::cout << "Calling base constructor" << std::endl; }
};

class Derived : public Base {
  public:
    using Base::Base;
    std::string member{"This is a member string"};
};

int main() {
  Derived d(1, 2, 3);
  std::cout << d.member << std::endl;
  return 0;
}

正如您所见[{3}},使用GCC编译上面的代码(并且没有优化)会生成Derived构造函数,并调用Base构造函数初始化std::string成员。

答案 2 :(得分:0)

是。虚方法在构造函数中非虚拟地调用,因为在调用基类构造函数时尚未构造派生类。

这是一种结束调用纯虚函数的已知方法 - 只需调用一些从构造函数调用纯虚函数的中间函数(你不能直接从构造函数调用纯虚函数,编译器不允许你)

要解决您的问题,而不是继承构造函数,请声明您自己的并调用基类构造函数,然后进行特定的初始化。