为什么以下示例会打印“0”,必须更改哪些内容才能按预期打印“1”?
#include <iostream>
struct base {
virtual const int value() const {
return 0;
}
base() {
std::cout << value() << std::endl;
}
virtual ~base() {}
};
struct derived : public base {
virtual const int value() const {
return 1;
}
};
int main(void) {
derived example;
}
答案 0 :(得分:90)
因为base
是先构建的,还没有“成熟”到derived
。当它无法保证对象已经正确初始化时,它无法调用对象上的方法。
答案 1 :(得分:20)
在构造派生对象时,在调用派生类构造函数的主体之前,必须完成基类构造函数。在调用派生类构造函数之前,构造中的对象的动态类型是基类实例而不是派生类实例。因此,当您从构造函数调用虚函数时,只能调用基类虚函数覆盖。
答案 2 :(得分:9)
实际上,有一种方法可以解决这种问题。 “软件中的每个问题都可以通过一定程度的间接解决。”
/* Disclaimer: I haven't done C++ in many months now, there might be a few syntax errors here and there. */
class parent
{
public:
parent( ) { /* nothing interesting here. */ };
protected:
struct parent_virtual
{
virtual void do_something( ) { cout << "in parent."; }
};
parent( const parent_virtual& obj )
{
obj.do_something( );
}
};
class child : public parent
{
protected:
struct child_virtual : public parent_virtual
{
void do_something( ) { cout << "in child."; }
};
public:
child( ) : parent( child_virtual( ) ) { }
};
答案 3 :(得分:4)
您不应该多态从构造函数中调用虚方法。 相反,你可以在构造对象后调用它们。
您的代码可以按如下方式重写
struct base {
virtual const int value() const {
return 0;
}
base() {
/* std::cout << value() << std::endl; */
}
virtual ~base() {}
};
struct derived : public base {
virtual const int value() const {
return 1;
}
};
int main(void) {
derived example;
std::cout << example.value() << std::endl;
}
答案 4 :(得分:3)
如何运作的问题 is a FAQ item 。
总结一下,在构造类T
时,动态类型为T
,它阻止对派生类函数实现的虚拟调用,如果允许则可以在相关类不变量建立之前执行代码(Java和C#中的常见问题,但C ++在这方面是安全的。)
如何在基类构造函数中执行派生类特定初始化的问题也是 a FAQ item ,直接遵循前面提到的。
总结一下,使用静态或动态多态可以将相关的函数实现传递给基类构造函数(或类)。
执行此操作的一种特殊方法是传递 “parts factory” object ,此参数可以默认。例如,一般Button
类可能会将按钮创建API函数传递给其Widget
基类构造函数,以便该构造函数可以创建正确的API级别对象。
答案 5 :(得分:0)
一般规则是你不要从构造函数中调用虚函数。
答案 6 :(得分:-4)
在C ++中,您无法从构造函数中调用virtual / overriden方法。
现在,有一个很好的理由可以做到这一点。作为“软件中的最佳实践”,您应该尽可能避免从构造函数中调用其他方法,甚至是非虚拟方法。
但是,规则总是有例外,因此您可能希望使用“伪构造方法”来模拟它们:
#include <iostream>
class base {
// <constructor>
base() {
// do nothing in purpouse
}
// </constructor>
// <destructor>
~base() {
// do nothing in purpouse
}
// </destructor>
// <fake-constructor>
public virtual void create() {
// move code from static constructor to fake constructor
std::cout << value() << std::endl;
}
// </fake-constructor>
// <fake-destructor>
public virtual void destroy() {
// move code from static destructor to fake destructor
// ...
}
// </fake-destructor>
public virtual const int value() const {
return 0;
}
public virtual void DoSomething() {
// std:cout << "Hello World";
}
};
class derived : public base {
// <fake-constructor>
public override void create() {
// move code from static constructor to fake constructor
std::cout << "Im pretending to be a virtual constructor," << std::endl;
std::cout << "and can call virtual methods" << std::endl;
}
// </fake-constructor>
// <fake-destructor>
public override void destroy() {
// move code from static destructor to fake destructor
std::cout << "Im pretending to be a virtual destructor," << std::endl;
std::cout << "and can call virtual methods" << std::endl;
}
// </fake-destructor>
public virtual const int value() const {
return 1;
}
};
int main(void) {
// call fake virtual constructor in same line, after real constructor
derived* example = new example(); example->create();
// do several stuff with your objects
example->doSomething();
// call fake virtual destructor in same line, before real destructor
example->destroy(); delete example();
}
作为一个加号,我建议程序员只使用“struct”作为字段结构,并使用“class”作为带有字段,方法,构造函数的结构......