来自构造函数的 C++ 虚函数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/496440/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 15:40:05  来源:igfitidea点击:

C++ virtual function from constructor

c++oopclassconstructorvirtual

提问by Giovanni Funchal

Why the following example prints "0" and what must change for it to print "1" as I expected ?

为什么下面的示例打印“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;
}

回答by Sean Bright

Because baseis constructed first and hasn't "matured" into a derivedyet. It can't call methods on an object when it can't guarantee that the object is already properly initialized.

因为base首先被构建并且还没有“成熟”成一个derived。当它不能保证对象已经正确初始化时,它不能调用对象的方法。

回答by CB Bailey

When a derived object is being constructed, before the body of the derived class constructor is called the base class constructor must complete. Before the derived class constructor is called the dynamic type of the object under construction is a base class instance and not a derived class instance. For this reason, when you call a virtual function from a constructor, only the base class virtual function overrides can be called.

在构造派生对象时,在调用派生类构造函数的主体之前,基类构造函数必须完成。在调用派生类构造函数之前,正在构造的对象的动态类型是基类实例而不是派生类实例。因此,当您从构造函数调用虚函数时,只能调用基类虚函数覆盖。

回答by Tanveer Badar

Actually, there is a way to get this behavior. "Every problem in software can be solved with a level of indirection."

实际上,有一种方法可以获得这种行为。“软件中的每个问题都可以通过间接级别来解决。”

/* 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( ) ) { }
};

回答by Cheers and hth. - Alf

The question of how it works is a FAQ item.

如何工作的问题是一个常见问题

Summarizing, while class Tis being constructed, the dynamic type is T, which prevents virtual calls to derived class function implementations, which if permitted could execute code before the relevant class invariant had been established (a common problem in Java and C#, but C++ is safe in this respect).

总而言之,在T构造类时,动态类型是T,这可以防止对派生类函数实现的虚拟调用,如果允许,可以在相关类不变量建立之前执行代码(Java 和 C# 中的常见问题,但 C++ 是安全的在这方面)。

The question of how to do derived class specific initialization in a base class constructor is also a FAQ item, directly following the previously mentioned one.

如何在基类构造函数中进行派生类特定初始化的问题也是常见问题解答项,紧接前面提到的一项。

Summarizing, using static or dynamic polymorphism on may pass the relevant function implementations up to the base class constructor (or class).

总之,使用静态或动态多态可以将相关的函数实现传递给基类构造函数(或类)。

One particular way to do that is to pass a “parts factory” objectup, where this argument can be defaulted. For example, a general Buttonclass might pass a button creation API function up to its Widgetbase class constructor, so that that constructor can create the correct API level object.

一种特殊的方法是向上传递一个“零件工厂”对象,这个参数可以被默认。例如,通用Button类可能会将按钮创建 API 函数传递给其Widget基类构造函数,以便该构造函数可以创建正确的 API 级别对象。

回答by Vinay

You should not polymorphicallycall the virtual methods from constructor. Instead you can call them after construction of object.

你不应该多态地从构造函数调用虚方法。相反,您可以在构造对象后调用它们。

Your code can be re written as follows

你的代码可以改写如下

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;
}

回答by Hank Gay

The general rule is you don't call a virtual function from a constructor.

一般规则是不要从构造函数调用虚函数。

回答by umlcat

In C++, you cannot call a virtual / overriden method from a constructor.

在 C++ 中,您不能从构造函数调用虚拟/覆盖方法。

Now, there is a good reason you can do this. As a "best practice in software", you should avoid calling additional methods from your constructor, even non virtual, as possible.

现在,您有充分的理由可以这样做。作为“软件中的最佳实践”,您应该尽可能避免从构造函数调用其他方法,即使是非虚拟方法。

But, there is always an exception to the rule, so you may want to use a "pseudo constructor method", to emulate them:

但是,规则总是有一个例外,因此您可能需要使用“伪构造函数方法”来模拟它们:

#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();
}

As a plus, I recommend programmers to use "struct" for only fields structures, and "class" for structures with fields, methods, constructors, ...

另外,我建议程序员仅对字段结构使用“struct”,对具有字段、方法、构造函数等的结构使用“class”。