为什么c++没有虚构造函数?


当前回答

总结:c++标准可以为“虚拟构造函数”指定一种表示法和行为,这是相当直观的,而且编译器也不难支持,但是为什么在已经可以使用create() / clone()清晰地实现功能的情况下(见下文),还要专门为此做出标准更改呢?它远不如正在酝酿中的许多其他语言提案那么有用。

讨论

让我们假设一个“虚拟构造函数”机制:

Base* p = new Derived(...);
Base* p2 = new p->Base();  // possible syntax???

在上面的代码中,第一行构造了一个Derived对象,因此*p的虚拟调度表可以合理地为第二行提供一个“虚拟构造函数”。(本页上有几十个回答说“这个物体还不存在,所以虚拟构建是不可能的”,这些答案都是不必要的短视地关注即将被构建的物体。)

第二行假设符号new p->Base()请求动态分配和另一个派生对象的默认构造。

注:

the compiler must orchestrate memory allocation before calling the constructor - constructors normally support automatic (informally "stack") allocation, static (for global/namespace scope and class-/function-static objects), and dynamic (informally "heap") when new is used the size of object to be constructed by p->Base() can't generally be known at compile-time, so dynamic allocation is the only approach that makes sense it is possible to allocate runtime-specified amounts of memory on the stack - e.g. GCC's variable-length array extension, alloca() - but leads to significant inefficiencies and complexities (e.g. here and here respectively) for dynamic allocation it must return a pointer so memory can be deleted later. the postulated notation explicitly lists new to emphasise dynamic allocation and the pointer result type.

编译器需要:

通过调用隐式的虚拟sizeof函数或通过RTTI获得这些信息,找出Derived需要多少内存 调用operator new(size_t)来分配内存 调用Derived(),位置为new。

OR

为结合了动态分配和构造的函数创建额外的虚表项

因此,指定和实现虚拟构造函数似乎并不是不可克服的,但最重要的问题是:它如何比使用现有的c++语言特性更好?就我个人而言,我认为下面的解决方案没有任何好处。


' clone() '和' create() '

c++常见问题解答文档中记录了一个“虚拟构造函数”习语,包含了用于默认构造或复制构造一个新的动态分配对象的虚拟create()和clone()方法:

class Shape {
  public:
    virtual ~Shape() { } // A virtual destructor
    virtual void draw() = 0; // A pure virtual function
    virtual void move() = 0;
    // ...
    virtual Shape* clone() const = 0; // Uses the copy constructor
    virtual Shape* create() const = 0; // Uses the default constructor
};
class Circle : public Shape {
  public:
    Circle* clone() const; // Covariant Return Types; see below
    Circle* create() const; // Covariant Return Types; see below
    // ...
};
Circle* Circle::clone() const { return new Circle(*this); }
Circle* Circle::create() const { return new Circle(); }

也可以更改或重载create()以接受参数,不过为了匹配基类/接口的虚函数签名,重写的参数必须精确匹配基类重载中的一个。有了这些用户提供的显式功能,添加日志记录、检测、更改内存分配等就变得很容易了。

其他回答

A virtual-table(vtable) is made for each Class having one or more 'virtual-functions'. Whenever an Object is created of such class, it contains a 'virtual-pointer' which points to the base of corresponding vtable. Whenever there is a virtual function call, the vtable is used to resolve to the function address. Constructor can not be virtual, because when constructor of a class is executed there is no vtable in the memory, means no virtual pointer defined yet. Hence the constructor should always be non-virtual.

听可靠消息。:)

选自Bjarne Stroustrup的c++风格和技术常见问题解答为什么没有虚拟构造函数?

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

FAQ条目继续给出了一种不使用虚拟构造函数实现此目的的方法的代码。

“构造函数不能是虚拟的”

有一些合理的理由可以证明这种说法是正确的。

要创建对象,对象类的构造函数必须与类的类型相同。但是,对于虚拟实现的构造函数,这是不可能的。 在调用构造函数时,还没有创建虚表来解析任何虚函数调用。因此,虚拟构造函数本身将没有任何可以查找的地方。


因此,不可能将构造函数声明为虚函数。

你也不应该在构造函数中调用虚函数。参见:http://www.artima.com/cppsource/nevercall.html

另外,我不确定是否真的需要虚拟构造函数。你可以在没有它的情况下实现多态构造:你可以编写一个函数,根据所需的参数构造你的对象。

When a constructor is invoked, although there is no object created till that point, we still know the kind of object that is gonna be created because the specific constructor of the class to which the object belongs to has already been called. Virtual keyword associated with a function means the function of a particular object type is gonna be called. So, my thinking says that there is no need to make the virtual constructor because already the desired constructor whose object is gonna be created has been invoked and making constructor virtual is just a redundant thing to do because the object-specific constructor has already been invoked and this is same as calling class-specific function which is achieved through the virtual keyword. Although the inner implementation won’t allow virtual constructor for vptr and vtable related reasons.

Another reason is that C++ is a statically typed language and we need to know the type of a variable at compile-time. The compiler must be aware of the class type to create the object. The type of object to be created is a compile-time decision. If we make the constructor virtual then it means that we don’t need to know the type of the object at compile-time(that’s what virtual function provide. We don’t need to know the actual object and just need the base pointer to point an actual object call the pointed object’s virtual functions without knowing the type of the object) and if we don’t know the type of the object at compile time then it is against the statically typed languages. And hence, run-time polymorphism cannot be achieved. Hence, Constructor won’t be called without knowing the type of the object at compile-time. And so the idea of making a virtual constructor fails.