参考虚拟构造函数的虚拟函数机制

Virtual function mechanism with reference to virtual constructor

本文关键字:虚拟 机制 函数 构造函数 参考      更新时间:2023-10-16

这是在一次采访中问我的问题。

如果Vtable是在编译时创建的,而vptr是在运行时分配给对象的,那么如果我们的类中有虚拟构造函数,为什么编译器会在编译时出错呢?

我解释了整个机制。但他更感兴趣的是"为什么编译时错误而不是运行时错误"

我告诉他,C++准则是这样写的,所以编译器在编译时会发送错误。

你能给我提供相同的原因吗

简单答案的小问题-因为C++中没有虚拟构造函数。


在ISO标准中,ISO/IEC 14882:2003和ISO/IEC 14882:2011,12.1施工人员,第4点:

构造函数不能是虚拟的(10.3)或静态的(9.4)。构造函数可以为const、volatile或const volatile对象调用。构造函数不应声明为const、volatile或const volatile(9.3.2)。const和volatile语义(7.1.5.1)不应用于正在构建的对象。只有当派生最多的对象(1.8)的构造函数结束时,这种语义才会生效。

这可以在编译时捕捉到。

为什么编译时错误而不是运行时错误

当运行时出现异常情况时,会发生运行时错误。而当编译器检测到C++标准不允许特定构造作为有效的C++构造时,就会发生编译时错误
C++标准不允许将构造函数标记为virtual。因此,编译器检测到它违反了语言语法规则并标记错误。

至于为什么C++中不允许使用虚拟构造函数
Bjarne在他的问题页面上回答问题为:

虚拟调用是一种在给定部分信息的情况下完成工作的机制。特别是,"虚拟"允许我们只知道任何接口而不知道对象的确切类型来调用函数。要创建对象,您需要完整的信息。特别是,你需要知道你想要创建的东西的确切类型。因此,"对构造函数的调用"不能是虚拟的。

语言的规则不允许这样做,因为拥有虚拟构造函数是没有意义的。如何调用此构造函数?C++中构造某个基类的不同派生实例的一种常见方法是工厂方法:

#include <memory>
// the parameters determine the derived type to be instantiated.
std::unique_ptr<IFoo> fooFactory(some parameters);

注意智能指针的选择应由所有权策略决定。此示例使用唯一所有权。

在C++中,"虚拟"意味着在运行时所做的工作将取决于对象的有效类,而不仅仅取决于变量的类型。

"虚拟"构造函数实际上是没有意义的,因为你还没有对象(你想构建一个对象),所以你没有可以依赖的类来做出决定。

有时,对于"虚拟构造函数",C++中的意图是一种模式,在这种模式中,您可以在不知道确切类的情况下构建对象。。。例如:

class Document {
    public:
        static Document *create(...);
    private:
        Document(...);
};
...
// Just use Document::create instead of new Document
std::unique_ptr<Document> p = Document::create(...);

在这种情况下,类的用户不能调用构造函数(它是私有的),但他们只能调用一个公共的静态方法,该方法将返回一个指向实例的指针。构造本身将由该函数处理,返回的对象不一定是Document实例,而是从Document派生的某个类的实例,该类是您不知道的,并且没有公开的。例如,这允许在运行时根据环境或对create的调用中指定的参数来决定确切的类。

这被称为"虚拟构造函数",因为被调用的构造函数将在运行时决定。然而,它与C++中的虚拟方法调用不同,因为C++中的虚调度只取决于实例的类(但正如前面所说,这对构造函数来说没有意义,因为对象还不存在,所以你不能根据它的真实类来决定)。