从基类构造函数中调用派生类的成员函数

时间:2015-03-12 22:33:56

标签: c++ inheritance

假设我有

struct C {
   C() { init(); };
   void init() { cout << "C" << endl; };
};

struct D : public C {
   D() : C() { };
   void init() { cout << "D" << endl; }
};

D();

为什么我得到&#34; C&#34;印?如何改变这种行为(并获得&#34; D&#34;)。

如果我想要两者?

3 个答案:

答案 0 :(得分:6)

  

为什么我会打印“C”?

C::init()未声明为virtual,因此D无法覆盖它。但即使C::init()被声明为virtualD::init()在<{1}}内调用init()时也不会调用 的构造函数。

C ++在派生类之前构造基类(并在基类之前销毁派生的clases)。因此C的构造函数在构造C之前运行(并且D的析构函数在C被破坏后运行)。正在构造/销毁的对象的VMT在构造/销毁D时不会指向D的方法表,而是指向C的方法表。 / p>

  

如何改变这种行为(并获得“D”)。

不能从基类构造函数/析构函数内部调用派生的虚方法。 VMT在这些阶段不包含指向派生类方法表的指针。

答案 1 :(得分:1)

这里有一个非常基本的问题:你想在一个尚不存在的对象上调用派生类的成员函数。

请记住,通过首先构造基础子对象然后构造派生对象来构造对象。因此,即使您设法应用“聪明”技巧来实际调用派生类'init函数,只要该函数尝试访问派生对象的任何数据成员,就会造成任意损坏。另一方面,只访问构造函数尚未建立的任何不变量,只访问基础对象即可。因此,如果您不需要访问派生对象的数据,则可以创建init函数static并将其传递给基类对象。

也许这接近你想要做的事情。

#include <iostream>

struct Base
{
  Base(void (*fp)(Base&) = Base::init) { fp(*this); }
  static void init(Base&) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};

struct Derived : Base
{
  Derived() : Base(Derived::init) { }
  static void init(Base&) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};

int
main()
{
  Base b {};
  std::cout << std::endl;
  Derived d {};
}

输出:

static void Base::init(Base&)

static void Derived::init(Base&)

这里,基类构造函数接受一个函数指针,该函数指向一个初始化函数,该函数接受对Base对象的引用。该函数默认为Base::init,但派生类可以替换它。但请注意,在此设计中,Base类构造函数可能无法安全地假设Base::init的任何副作用实际发生。它可以作为一种扩展机制(如果Base::init什么也不做或者是一次性的)。

但我怀疑你需要使用这种机器。如果您只想做 - 而且这应该是正常的情况 - 首先初始化基础对象然后初始化派生对象,如果您只是从相应的构造函数调用函数,C ++已经默认执行正确的操作。

struct Base
{
  Base() { this->init(); }
  void init() { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};

struct Derived : Base
{
  Derived() { this->init(); }
  void init() { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};

// main() as above ...

输出:

void Base::init()

void Base::init()
void Derived::init()

如果我们只想调用派生类最多的类init,我们可以简单地告诉基类不要运行它自己的。

struct Base
{
  Base(const bool initialize = true) { if (initialize) this->init(); }
  void init() { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};

struct Derived : Base
{
  Derived() : Base(false) { this->init(); }
  void init() { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};

// main() as above ...

输出:

void Base::init()

void Derived::init()

答案 2 :(得分:-2)

您只能从C构造函数中删除init()以不打印&#34; C&#34;。 还打印&#34; D&#34;在init()构造函数中添加D()

如果在某些情况下你想要打印&#34; C&#34;或&#34; D&#34;在某些人做不到这样的事情

struct C {
   C() { };
   void init() { cout << "C" << endl; };
};

struct D : public C {
   D() : C() 
   { 
     if(some condition)
       C::init();

     if(some condition)
       init();
   };

   void init() { cout << "D" << endl; }
};

D();