假设我有
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;)。
如果我想要两者?
答案 0 :(得分:6)
为什么我会打印“C”?
C::init()
未声明为virtual
,因此D
无法覆盖它。但即使C::init()
被声明为virtual
,D::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();