这是在一次采访中向我提出的问题。
如果在编译时创建了Vtable,并且在运行时将vptr
分配给了对象,那么如果我们的类中有虚拟构造函数,为什么编译器会给出编译时错误?
我解释了整个机制。但他对'为什么编译时错误而不是运行时错误'
更感兴趣我告诉他,C ++指南是这样的,因此编译器会在编译时发送错误。
你能否告诉我同样的原因
答案 0 :(得分:9)
简单回答的棘手问题 - 因为C++
中有 no 虚拟构造函数。
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)的构造函数结束时,这种语义才会生效。
这可以在编译时捕获。
答案 1 :(得分:5)
为什么编译时错误而不是运行时错误?
运行时发生异常情况时会发生运行时错误。当编译器检测到C ++标准不允许特定构造作为有效的C ++构造时,会发生编译时错误
C ++标准不允许将构造函数标记为virtual
。因此,编译器将其检测为违反语言语法规则并标记错误。
至于回答为什么在C ++中不允许使用虚构造函数 Bjarne在他的常见问题页面上回答Q:
虚拟调用是一种在给定部分信息的情况下完成工作的机制。特别是,“virtual”允许我们只知道任何接口而不是对象的确切类型来调用函数。要创建对象,您需要完整的信息。特别是,您需要知道要创建的内容的确切类型。因此,“对构造函数的调用”不能是虚拟的。
答案 2 :(得分:3)
语言规则不允许,因为拥有虚拟构造函数没有意义。如何调用此构造函数? C ++中用于构造某个基类的不同派生实例的常用方法是工厂方法:
#include <memory>
// the parameters determine the derived type to be instantiated.
std::unique_ptr<IFoo> fooFactory(some parameters);
注意 smart pointer的选择应由所有权政策决定。此示例使用唯一所有权。
答案 3 :(得分:-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 ++中的虚拟调度仅依赖于实例的类(但如前所述,对于构造函数没有意义,因为该对象尚不存在,所以你不能根据其真实的类别来决定。)