【问题标题】:Virtual constructor and what happens calling virtual functions inside it虚拟构造函数以及在其中调用虚拟函数会发生什么
【发布时间】:2013-04-02 20:12:05
【问题描述】:

我有两个问题,我在这里找到的答案并不完全让我满意:

  • 为什么将构造函数声明为 virtual 没有意义?
  • 当我从构造函数调用虚函数时会发生什么?虚拟表也用了吗?

【问题讨论】:

标签: c++ oop object


【解决方案1】:

为什么将构造函数声明为虚拟是没有意义的?

在构造函数执行之前,对象是不存在的,所以不存在override这样的东西。

当我从构造函数调用虚函数时会发生什么?虚拟表也用了吗?

可以。在大多数情况下,如果直接从构造函数执行调用,编译器可以跳过动态调度,因为此时它知道最终的覆盖器是什么。但它不需要执行该优化,即使它可以直接在构造函数中执行此操作,但如果您调用一个非虚拟函数又调用该虚拟函数,它也无法执行此操作。因为非虚函数可能会被派生类型的对象调用,所以它必须使用虚调度机制。

【讨论】:

    【解决方案2】:

    当调用构造函数时,(尚不存在的)对象的实际类型是非常确定的。所以调用构造函数永远不会是间接的。 (通过指针/引用调用时,仅间接调用虚函数。)

    BaseClass *x = new SubClass();
    

    在构造函数中调用虚函数并不符合您的预期。由于子类还没有初始化,所以最终类上的虚函数不能被调用(v-table当前指向当前正在执行的构造函数的类)。

    class BaseClass {
        BaseClass() {
            call();
        }
        virtual void call() {
            std::cout << "BaseClass!";
        }
    };
    
    class SubClass : public BaseClass {
        SubClass() : BaseClass()
        {
        }
    
        void call() {
            std::cout << "SubClass!";
        }
    };
    

    http://ideone.com/9aQVIc

    【讨论】:

    • 从构造函数调用虚函数不是未定义的行为。标准中完美定义了在构造类型级别调用 final overrider
    • 已更正。我不确定;我知道我会记错。现在我想起了。请参阅我的更正。
    • @David 所以澄清一下,如果你有class SubSubClass : public SubClass,并且你试图从SubClass的构造函数调用call(),它会调用SubClass::call()
    • 是的。当一个类的构造函数被调用时,它与你实际构造这个类的一个实例(而不是一个子类)是一样的。 (确实,此时此刻,正在构造这个类的一个实例。在那之前仅此而已。子类的构造函数总是首先调用超类的构造函数。)
    • @JBentley:在 C++ 中,对象的类型在构造/销毁期间会发生变化。在每一层,它都是被调用的构造函数/析构函数的类型。所以是的,SubClass 的构造函数中的代码call(); 不会被调度到层次结构中的SubClass 点下方,即使正在构建的完整对象是SubSubSub...Class
    【解决方案3】:

    Why declaring a constructor as virtual is meaningless.

    当调用构造函数时,虚拟表在内存中将不可用。在 C++ 中声明一些虚拟的东西意味着它可以被当前类的子类覆盖,但是在创建对象时调用构造函数,那时你不能创建你必须的类的子类创建类,因此永远不需要声明构造函数虚拟。因此,C++ 中不存在virtual constructor 这样的东西。

    What happens when I call a virtual function from a constructor? Is the virtual table used too

    有关此问题的详细说明,请参阅C++ FAQ 链接。

    【讨论】:

      猜你喜欢
      • 2010-09-09
      • 2012-04-13
      • 2012-04-12
      • 2016-04-09
      • 2010-09-12
      • 2016-01-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多