class MyClass1
{
public:
MyClass1()
{
init();
}
virtual void init()
{
printf("MyClass1 init");
}
}
class MyClass2 : public MyClass1
{
public:
virtual void init()
{
printf("MyClass2 init");
}
}
int main()
{
MyClass2 *obj = new MyClass2();
return 0;
}
我想结果
"MyClass2 init"
但它显示了实际上的消息
"MyClass1 init"
如何从基类构造函数调用派生类虚方法?
=== update1 ===
class MyClass1
{
public:
MyClass1()
{
init();
}
virtual void init()
{
printf("MyClass1 init");
}
}
class MyClass2 : public MyClass1
{
public:
MyClass2()
: MyClass1()
{
}
virtual void init()
{
printf("MyClass2 init");
}
}
我希望MyClass2覆盖MyClass1 init方法 但它仍然显示“MyClass1 init”
C ++如何像java / C#覆盖方法一样工作?
=== update2 ===
class MyClass1
{
public:
MyClass1()
{
init(); <--- can't work like test method ???
}
void test()
{
init(); <--- work fine
}
virtual void init()
{
printf("MyClass1 init");
}
}
class MyClass2 : public MyClass1
{
public:
MyClass2()
: MyClass1()
{
}
virtual void init()
{
printf("MyClass2 init");
}
}
我知道obj-&gt; init()将调用MyClass2 :: init。
但我希望C ++可以在Constructor方法中运行。
虽然可以解析obj-&gt; init()。
但我希望代码写得少一些。
有些人忘了打电话给init()。
答案 0 :(得分:2)
一般来说,你不能。那是因为MyClass2
构造函数尚未运行,因此如果要调用MyClass2::init()
,则任何成员变量都将是未初始化的。在启动此构造函数之前,出于虚拟目的,该对象被视为MyClass1
实例。
例如:
class MyClass2 : public MyClass1
{
private:
std::string xxx;
public:
virtual void init()
{
xxx = "ops!"; //undefined if called from base class constructor
}
};
xxx
的赋值将呈现未定义的行为,因为它的构造函数尚未运行。
鉴于你缺少结尾;
,我猜你在Java / C#中的背景。这些语言以不同的方式实现了这个问题,但这就是C ++的工作原理。
答案 1 :(得分:2)
显然在构造MyClass2
期间,MyClass1
的构造函数将首先被调用,
派生类对象的基类部分是在派生类部件之前构造的。即使你明确地尝试创建MyClass2
的对象,但在基类构造期间,虚函数永远不会进入派生类。
因为基类构造函数在派生类构造函数之前执行,所以在基类构造函数运行时尚未初始化派生类数据成员。如果在基类构造期间调用的虚函数归结为派生类,派生类函数几乎肯定会引用本地数据成员,但这些数据成员尚未初始化,这将导致未定义的行为。
请参阅您的课程,为什么首先考虑virtual init
?构造者应分别完成工作。
如何从基类构造函数调用派生类虚方法?
这是个坏主意,永远不应该这样做!
class MyClass1
{
public:
virtual ~MyClass1() { }
virtual void doSomething()
{
printf("MyClass1 init");
}
};
class MyClass2 : public MyClass1
{
public:
virtual void doSomething()
{
printf("MyClass2 init");
}
};
int main()
{
MyClass1*obj = new MyClass2();
obj->doSomething();
delete obj;
return 0;
}
答案 2 :(得分:0)
我认为:
没理由C ++不能做java / C#虚拟构造机制
我想打破C ++规则。
我也希望C ++可以少花钱多做
如果C ++没有改进,就不会有进步,所以更多的人不能轻易进入。
class MyClass1
{
public:
MyClass1()
{
init();
}
typedef void (MyClass1::virtual_init)();
MyClass1(virtual_init vinit)
{
(this->*vinit)();
}
//virtual void init()
void init()
{
printf("MyClass1 init");
}
}
class MyClass2 : public MyClass1
{
public:
MyClass2()
: MyClass1(&MyClass2::init)
{
}
//virtual void init()
void init()
{
printf("MyClass2 init");
}
}
答案 3 :(得分:0)
我不确定这是否合法或将来可能会中断。但是,使用lambda函数,您可以将代码发送到基类,以在构造函数期间执行。
class Base {
public:
Base(std::function<void()> fnCall=nullptr) {
if (fnCall) fnCall();
}
Base(const Base &base, std::function<void()> fnCall = nullptr) {
DoSomethingAtBaseHere();
if (fnCall) fnCall();
}
};
class Derived: public Base {
public:
Derived(std::function<void()> fnCall=nullptr) : Base([&]() {
DoSomethingAtDerivedHere();
if (fnCall) fnCall();
}) {}
Derived(const Derived &oth, std::function<void()> fnCall=nullptr) :
Base(oth, [&]() {
DoSomethingInCopyConstructorAtDerivedHere();
if (fnCall) fnCall();
}) {}
};