1

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

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

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

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

你能告诉我同样的原因吗

4

4 回答 4

9

简单回答的棘手问题 - 因为在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) 的构造函数结束后才生效。

这可以在编译时捕获。

于 2012-08-29T12:14:23.793 回答
5

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

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

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

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

于 2012-08-29T12:18:18.623 回答
3

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

#include <memory>

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

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

于 2012-08-29T12:18:30.197 回答
-1

在 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++ 中的虚拟调度仅取决于实例的类(但如前所述,这对构造函数没有意义,因为对象还不存在,所以你不能决定取决于它的真实类)。

于 2012-08-29T12:20:27.953 回答