为什么在c++中没有虚拟构造函数呢?

时间:2021-11-26 22:26:27

Why does C++ not have a virtual constructor?

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

20 个解决方案

#1


194  

Hear it from the horse's mouth:).

从马嘴里听到:)。

From Bjarne Stroustrup's C++ Style and Technique FAQ Why don't we have virtual constructors?

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

A virtual call is a mechanism to get work done given partial information. In particular, "virtual" allows us to call a function knowing only any interfaces and not the exact type of the object. To create an object you need complete information. In particular, you need to know the exact type of what you want to create. Consequently, a "call to a constructor" cannot be virtual.

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

The FAQ entry goes on to give the code for a way to achieve this end without a virtual constructor.

FAQ条目继续为实现这一目的提供代码,而无需使用虚拟构造函数。

#2


117  

Virtual functions basically provide polymorphic behavior. That is, when you work with an object whose dynamic type is different than the static (compile time) type with which it is referred to, it provides behavior that is appropriate for the actual type of object instead of the static type of the object.

虚函数基本上提供了多态行为。也就是说,当您处理的对象的动态类型与引用它的静态(编译时)类型不同时,它提供的行为适合对象的实际类型,而不是对象的静态类型。

Now try to apply that sort of behavior to a constructor. When you construct an object the static type is always the same as the actual object type since:

现在尝试将这种行为应用到构造函数中。当您构造一个对象时,静态类型始终与实际对象类型相同:

To construct an object, a constructor needs the exact type of the object it is to create [...] Furthermore [...]you cannot have a pointer to a constructor

要构造一个对象,构造函数需要创建的对象的确切类型。]此外[…不能有指向构造函数的指针

(Bjarne Stroustup (P424 The C++ Programming Language SE))

(Bjarne Stroustup (P424 c++编程语言SE))

#3


55  

Unlike object oriented languages such as Smalltalk or Python, where the constructor is a virtual method of the object representing the class (which means you don't need the GoF abstract factory pattern, as you can pass the object representing the class around instead of making your own), C++ is a class based language, and does not have objects representing any of the language's constructs. The class does not exist as an object at runtime, so you can't call a virtual method on it.

与面向对象的语言(如Smalltalk或Python,构造函数是一个虚拟方法的对象代表类(这意味着你不需要GoF抽象工厂模式,可以通过代表类的对象,而不是让你自己的),c++是一种基于类的语言,和没有对象代表的任何语言的结构。类在运行时不作为对象存在,因此不能在其上调用虚拟方法。

This fits with the 'you don't pay for what you don't use' philosophy, though every large C++ project I've seen has ended up implementing some form of abstract factory or reflection.

这符合“不花钱买不使用的东西”的理念,尽管我看到的每个大型c++项目最终都实现了某种形式的抽象工厂或反射。

#4


35  

two reasons I can think of:

我可以想到两个原因:

Technical reason

技术原因

The object exists only after the constructor ends.In order for the constructor to be dispatched using the virtual table , there has to be an existing object with a pointer to the virtual table , but how can a pointer to the virtual table exist if the object still doesn't exist? :)

对象仅在构造函数结束后才存在。为了使用虚拟表分派构造函数,必须有一个具有指向虚拟表的指针的现有对象,但是如果对象仍然不存在,那么指向虚拟表的指针又如何存在呢?:)

Logic reason

逻辑的原因

You use the virtual keyword when you want to declare a somewhat polymorphic behaviour. But there is nothing polymorphic with constructors , constructors job in C++ is to simply put an object data on the memory . Since virtual tables (and polymorphism in general) are all about polymorphic behaviour rather on polymorphic data , There is no sense with declaring a virtual constructor.

当您想要声明某种多态行为时,您可以使用虚拟关键字。但是对于构造函数来说没有什么多态性,在c++中构造函数的工作就是把对象数据放在内存中。由于虚拟表(以及通常的多态性)都是关于多态性行为,而不是关于多态性数据,因此声明虚拟构造函数是没有意义的。

#5


11  

We do, it's just not a constructor :-)

是的,它不是构造函数

struct A {
  virtual ~A() {}
  virtual A * Clone() { return new A; }
};

struct B : public A {
  virtual A * Clone() { return new B; }
};

int main() {

   A * a1 = new B;
   A * a2 = a1->Clone();    // virtual construction
   delete a2;
   delete a1;
}

#6


11  

Semantic reasons aside, there is no vtable until after the object is constructed, thus making a virtual designation useless.

除了语义上的原因,在对象被构造之后才会有vtable,因此虚拟指定是无用的。

#7


8  

Summary: the C++ Standard could specify a notation and behaviour for "virtual constructor"s that's reasonably intuitive and not too hard for compilers to support, but why make a Standard change for this specifically when the functionality can already be cleanly implemented using create() / clone() (see below)? It's not nearly as useful as many other language proposal in the pipeline.

概述:c++标准可以为“虚拟构造函数”指定一种符号和行为,这种符号和行为是相当直观的,编译器不太难以支持,但是为什么要为此做一个标准更改呢?它远不如许多其他语言提案有用。

Discussion

Let's postulate a "virtual constructor" mechanism:

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

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

In the above, the first line constructs a Derived object, so *p's virtual dispatch table can reasonably supply a "virtual constructor" for use in the second line. (Dozens of answers on this page stating "the object doesn't yet exist so virtual construction is impossible" are unnecessarily myopically focused on the to-be-constructed object.)

在上面,第一行构造了一个派生对象,因此*p的虚拟分派表可以合理地提供一个“虚拟构造函数”用于第二行。(在这个页面上,有几十个答案说明“这个对象还不存在,所以虚拟构建是不可能的”,这是不必要地把注意力集中在将要构建的对象上。)

The second line postulates the notation new p->Base() to request dynamic allocation and default construction of another Derived object.

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

Notes:

注:

  • 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

      p->Base()构造的对象的大小通常不能在编译时被知道,所以动态分配是唯一有意义的方法

      • 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)
      • 可以在堆栈上分配运行时指定的内存数量——例如GCC的可变长度数组扩展alloca()——但是会导致显著的低效和复杂性(例如这里和这里)
  • 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.

    假定的表示法明确列出了强调动态分配和指针结果类型的新内容。

The compiler would need to:

编译器将需要:

  • find out how much memory Derived needed, either by calling an implicit virtual sizeof function or having such information available via RTTI
  • 通过调用隐式虚拟sizeof函数或通过RTTI获得此类信息,找出需要多少内存
  • call operator new(size_t) to allocate memory
  • 调用操作符new(size_t)来分配内存
  • invoke Derived() with placement new.
  • 使用新的位置调用派生()。

OR

  • create an extra vtable entry for a function that combines dynamic allocation and construction
  • 为一个结合动态分配和构造的函数创建一个额外的vtable条目。

So - it doesn't seem insurmountable to specify and implement virtual constructors, but the million-dollar question is: how would it be better than what's possible using existing C++ language features...? Personally, I see no benefit over the solution below.

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


`clone()` and `create()`

The C++ FAQ documents a "virtual constructor" idiom, containing virtual create() and clone() methods to default-construct or copy-construct a new dynamically-allocated object:

c++ FAQ文档中有一个“虚拟构造函数”习语,包含虚拟创建()和克隆()方法,用于默认构造或复制构造一个新的动态分配的对象:

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(); }

It's also possible to change or overload create() to accept arguments, though to match the base class / interface's virtual function signature, arguments to overrides must exactly match one of the base class overloads. With these explicit user-provided facilities, it's easy to add logging, instrumentation, alter memory allocation etc..

也可以更改或重载create()来接受参数,但是要匹配基类/接口的虚函数签名,重写的参数必须与基类重载中的一个完全匹配。有了这些明确的用户提供的工具,很容易添加日志记录、插装、修改内存分配等。

#8


3  

Although the concept of virtual constructors does not fit in well since object type is pre-requisite for object creation, its not completly over-ruled.

虽然虚拟构造函数的概念并不适合,因为对象类型是创建对象的先决条件,但它并没有完全被过度控制。

GOF's 'factory method' design pattern makes use of the 'concept' of virtual constructor, which is handly in certain design situations.

GOF的“工厂方法”设计模式利用了虚拟构造函数的“概念”,在某些设计情况下非常方便。

#9


3  

Virtual functions are used in order to invoke functions based on the type of object pointed to by the pointer, and not the type of pointer itself. But a constructor is not "invoked". It is called only once when an object is declared. So, a constructor cannot be made virtual in C++.

虚函数用于根据指针指向的对象类型而不是指针本身的类型调用函数。但是构造函数不会被“调用”。当一个对象被声明时,它只被调用一次。因此,构造函数不能在c++中成为虚拟的。

#10


2  

You shouldn't call virtual function within your constructor either. See : http://www.artima.com/cppsource/nevercall.html

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

In addition I'm not sure that you really need a virtual constructor. You can achieve polymorphic construction without it: you can write a function that will construct your object according to the needed parameters.

此外,我不确定您是否真的需要一个虚拟构造函数。您可以不使用它来实现多态结构:您可以编写一个函数,根据需要的参数来构造对象。

#11


2  

When people ask a question like this, I like to think to myself "what would happen if this were actually possible?" I don't really know what this would mean, but I guess it would have something to do with being able to override the constructor implementation based on the dynamic type of the object being created.

当人们问这样的问题时,我喜欢对自己说“如果这是可能的,会发生什么?”我不知道这意味着什么,但我想这可能与能够基于创建的对象的动态类型重写构造函数实现有关。

I see a number of potential problems with this. For one thing, the derived class will not be fully constructed at the time the virtual constructor is called, so there are potential issues with the implementation.

我看到了一些潜在的问题。首先,在调用虚拟构造函数时,派生类不会被完全构造,因此实现中存在潜在的问题。

Secondly, what would happen in the case of multiple inheritance? Your virtual constructor would be called multiple times presumably, you would then need to have some way of know which one was being called.

第二,在多重继承的情况下会发生什么?您的虚拟构造函数可能会被多次调用,因此您需要有一些方法来知道调用了哪一个。

Thirdly, generally speaking at the time of construction, the object does not have the virtual table fully constructed, this means it would require a large change to the language specification to allow for the fact that the dynamic type of the object would be known at construction time. This would then allow the base class constructor to maybe call other virtual functions at construction time, with a not fully constructed dynamic class type.

第三,一般来说,在构建时,对象没有完整地构造虚拟表,这意味着需要对语言规范进行较大的更改,以允许在构建时了解对象的动态类型。然后,这将允许基类构造函数在构建时调用其他虚拟函数,并使用未完全构造的动态类类型。

Finally, as someone else has pointed out you can implement a kind of virtual constructor using static "create" or "init" type functions that basically do the same thing as a virtual constructor would do.

最后,正如其他人指出的那样,您可以使用静态的“创建”或“init”类型函数实现一种虚拟构造函数,这些函数基本上与虚拟构造函数所做的事情相同。

#12


2  

Virtual functions in C++ are an implementation of run-time polymorphism, and they will do function overriding. Generally the virtual keyword is used in C++ when you need dynamic behavior. It will work only when object exists. Whereas constructors are used to create the objects. Constructors will be called at the time of object creation.

c++中的虚函数是运行时多态性的实现,它们将执行函数覆盖。通常,当您需要动态行为时,在c++中使用virtual关键字。只有对象存在时,它才会工作。而构造函数用于创建对象。在创建对象时将调用构造函数。

So if you create the constructor as virtual, as per the virtual keyword definition, it should have existing object to use, but constructor is used to to create the object, so this case will never exist. So you should not use the constructor as virtual.

因此,如果按照virtual关键字定义将构造函数创建为virtual,则应该使用已有的对象,但是使用构造函数来创建对象,因此这种情况永远不会存在。因此,不应该将构造函数用作虚函数。

So, if we try to declare virtual constructor compiler throw an Error:

因此,如果我们试图声明虚拟构造函数编译器抛出一个错误:

Constructors cannot be declared virtual

构造函数不能声明为虚

#13


2  

You can find an example and the technical reason to why it is not allowed in @stefan 's answer. Now a logical answer to this question according to me is:

你可以在@stefan的回答中找到一个例子和技术原因。对于这个问题,我有一个合理的答案:

The major use of virtual keyword is to enable polymorphic behaviour when we don't know what type of the object the base class pointer will point to.

virtual关键字的主要用途是在我们不知道基类指针指向的对象的类型时启用多态行为。

But think of this is more primitive way, for using virtual functionality you will require a pointer. And what does a pointer require? An object to point to! (considering case for correct execution of the program)

但这是一种更原始的方式,对于使用虚拟功能,您将需要一个指针。指针需要什么?一个指向的对象!(考虑正确执行程序的情况)

So, we basically require an object that already exists somewhere in the memory (we are not concerned with how the memory was allocated, it may be at compile time or either runtime) so that our pointer can correctly point to that object.

因此,我们基本上需要一个已经存在于内存中的对象(我们不关心内存是如何分配的,它可能在编译时或者运行时),这样我们的指针就可以正确地指向那个对象。

Now, think of the situation about the moment when the object of the class to be pointed is being assigned some memory -> Its constructor will be called automatically at that instance itself!

现在,考虑一下当类的对象被分配到某个内存时,它的构造函数会自动被调用到那个实例本身!

So we can see that we don't actually need to worry about the constructor being virtual, because in any of the cases you wish to use a polymorphic behaviour our constructor would have already been executed making our object ready for usage!

因此,我们可以看到,我们实际上并不需要担心构造函数是虚拟的,因为在任何情况下,您希望使用多态行为,我们的构造函数就已经执行了,使我们的对象可以随时使用!

#14


1  

The virtual mechanism only works when you have a based class pointer to a derived class object. Construction has it's own rules for the calling of base class constructors, basically base class to derived. How could a virtual constructor be useful or called? I don't know what other languages do, but I can't see how a virtual constructor could be useful or even implemented. Construction needs to have taken place for the virtual mechanism to make any sense and construction also needs to have taken place for the vtable structures to have been created which provides the mechanics of the polymorphic behaviour.

虚拟机制只在具有到派生类对象的基于类指针时才工作。构造有它自己的调用基类构造函数的规则,基本是基类派生的规则。虚拟构造函数如何有用或调用?我不知道其他语言做什么,但我看不出虚拟构造函数是如何有用的,甚至是如何实现的。为了使虚拟机制变得有意义,需要进行构建,并且还需要构建vtable结构,以提供多态性行为的机制。

#15


1  

Cant we simply say it like.. We cannot inherit constructors. So there is no point declaring them virtual because the virtual provides polymorphism .

我们不能就这么说吗我们不能继承的构造函数。因此,没有必要将它们声明为虚,因为虚提供了多态性。

#16


1  

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.

一个虚拟表(vtable)是为每个拥有一个或多个“虚拟函数”的类而创建的。每当创建此类对象时,它都包含一个指向相应vtable基础的“虚拟指针”。只要有虚函数调用,就使用vtable解析函数地址。构造函数不能是虚拟的,因为当一个类的构造函数被执行时,在内存中没有vtable,意味着没有定义的虚拟指针。因此构造函数应该始终是非虚的。

#17


0  

C++ virtual constructor is not possible.For example you can not mark a constructor as virtual.Try this code

不可能使用c++虚拟构造函数。例如,不能将构造函数标记为虚。试试这个代码

#include<iostream.h>
using namespace std;
class aClass
{
    public:
        virtual aClass()
        {   
        }  
};
int main()
{
    aClass a; 
}

It causes an error.This code is trying to declare a constructor as virtual. Now let us try to understand why we use virtual keyword. Virtual keyword is used to provide run time polymorphism. For example try this code.

它会导致一个错误。这段代码试图将构造函数声明为虚拟的。现在让我们尝试理解为什么我们使用virtual关键字。Virtual关键字用于提供运行时多态性。例如,试试这段代码。

#include<iostream.h>
using namespace std;
class aClass
{
    public:
        aClass()
        {
            cout<<"aClass contructor\n";
        }
        ~aClass()
        {
            cout<<"aClass destructor\n";
        }

};
class anotherClass:public aClass
{

    public:
        anotherClass()
        {
            cout<<"anotherClass Constructor\n";
        }
        ~anotherClass()
        {
            cout<<"anotherClass destructor\n";
        }

};
int main()
{
    aClass* a;
    a=new anotherClass;
    delete a;   
    getchar(); 
}

In main a=new anotherClass; allocates a memory for anotherClass in a pointer a declared as type of aClass.This causes both the constructor (In aClass and anotherClass) to call automatically.So we do not need to mark constructor as virtual.Because when an object is created it must follow the chain of creation (i.e first the base and then the derived classes). But when we try to delete a delete a; it causes to call only the base destructor.So we have to handle the destructor using virtual keyword. So virtual constructor is not possible but virtual destructor is.Thanks

在主= new anotherClass;在一个被声明为aClass类型的指针中为另一个类分配一个内存。这会导致构造函数(在aClass和其他类中)自动调用。因此,我们不需要将构造函数标记为virtual。因为当一个对象被创建时,它必须遵循创建链(i)。首先是基础,然后是派生类。但是当我们试图删除一个删除的时候;它只调用基析构函数。所以我们必须使用virtual关键字来处理析构函数。所以虚拟构造函数是不可能的但是虚拟析构函数是。谢谢

#18


0  

There's a very basic reason: Constructors are effectively static functions, and in C++ no static function can be virtual.

有一个非常基本的原因:构造函数实际上是静态函数,在c++中没有静态函数可以是虚函数。

If you have much experience with C++, you know all about the difference between static & member functions. Static functions are associated with the CLASS, not the objects (instances), so they don't see a "this" pointer. Only member functions can be virtual, because the vtable- the hidden table of function pointers that makes 'virtual' work- is really a data member of each object.

如果您有很多c++的经验,您就会了解静态函数和成员函数之间的差异。静态函数与类相关联,而不是对象(实例),因此它们不会看到“this”指针。只有成员函数可以是虚的,因为vtable——使“虚”工作的函数指针的隐藏表——实际上是每个对象的数据成员。

Now, what is the constructor's job? It is in the name- a "T" constructor initializes T objects as they're allocated. This automatically precludes it being a member function! An object has to EXIST before it has a "this" pointer and thus a vtable. That means that even if the language treated constructors as ordinary functions (it doesn't, for related reasons I won't get into), they'd have to be static member functions.

构造函数的工作是什么?它在名称中——“T”构造函数在分配T对象时初始化它们。这自动排除了它是一个成员函数!一个对象必须在有一个“this”指针和一个vtable之前存在。这意味着,即使语言将构造函数视为普通函数(出于相关原因,我不会深入讨论),它们也必须是静态成员函数。

A great way to see this is to look at the "Factory" pattern, especially factory functions. They do what you're after, and you'll notice that if class T has a factory method, it is ALWAYS STATIC. It has to be.

查看这一点的一个好方法是查看“工厂”模式,特别是工厂功能。它们做你想做的,你会注意到如果类T有一个工厂方法,它总是静态的。它必须是。

#19


-1  

The Vpointer is created at the time of object creation. vpointer wont exists before object creation. so there is no point of making the constructor as virtual.

Vpointer是在创建对象时创建的。在创建对象之前,vpointer不存在。因此,将构造函数设为虚函数是毫无意义的。

#20


-1  

If you think logically about how constructors work and what the meaning/usage of a virtual function is in C++ then you will realise that a virtual constructor would be meaningless in C++. Declaring something virtual in C++ means that it can be overridden by a sub-class of the current class, however the constructor is called when the objected is created, at that time you cannot be creating a sub-class of the class, you must be creating the class so there would never be any need to declare a constructor virtual.

如果您逻辑地思考构造函数的工作方式,以及在c++中虚拟函数的含义/用法,那么您将认识到,在c++中虚拟构造函数是没有意义的。在c++中声明一些虚拟意味着它可以覆盖当前类的子类,但是调用构造函数创建反对时,那时你不能创建一个类的子类,您必须创建类所以不会有任何需要声明一个构造函数的虚拟。

And another reason is, the constructors have the same name as its class name and if we declare constructor as virtual, then it should be redefined in its derived class with the same name, but you can not have the same name of two classes. So it is not possible to have a virtual constructor.

另一个原因是,构造函数的名称与其类名相同,如果我们将构造函数声明为virtual,那么它应该在它的派生类中以相同的名称重新定义,但是两个类的名称不能相同。所以不可能有一个虚拟构造函数。

#1


194  

Hear it from the horse's mouth:).

从马嘴里听到:)。

From Bjarne Stroustrup's C++ Style and Technique FAQ Why don't we have virtual constructors?

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

A virtual call is a mechanism to get work done given partial information. In particular, "virtual" allows us to call a function knowing only any interfaces and not the exact type of the object. To create an object you need complete information. In particular, you need to know the exact type of what you want to create. Consequently, a "call to a constructor" cannot be virtual.

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

The FAQ entry goes on to give the code for a way to achieve this end without a virtual constructor.

FAQ条目继续为实现这一目的提供代码,而无需使用虚拟构造函数。

#2


117  

Virtual functions basically provide polymorphic behavior. That is, when you work with an object whose dynamic type is different than the static (compile time) type with which it is referred to, it provides behavior that is appropriate for the actual type of object instead of the static type of the object.

虚函数基本上提供了多态行为。也就是说,当您处理的对象的动态类型与引用它的静态(编译时)类型不同时,它提供的行为适合对象的实际类型,而不是对象的静态类型。

Now try to apply that sort of behavior to a constructor. When you construct an object the static type is always the same as the actual object type since:

现在尝试将这种行为应用到构造函数中。当您构造一个对象时,静态类型始终与实际对象类型相同:

To construct an object, a constructor needs the exact type of the object it is to create [...] Furthermore [...]you cannot have a pointer to a constructor

要构造一个对象,构造函数需要创建的对象的确切类型。]此外[…不能有指向构造函数的指针

(Bjarne Stroustup (P424 The C++ Programming Language SE))

(Bjarne Stroustup (P424 c++编程语言SE))

#3


55  

Unlike object oriented languages such as Smalltalk or Python, where the constructor is a virtual method of the object representing the class (which means you don't need the GoF abstract factory pattern, as you can pass the object representing the class around instead of making your own), C++ is a class based language, and does not have objects representing any of the language's constructs. The class does not exist as an object at runtime, so you can't call a virtual method on it.

与面向对象的语言(如Smalltalk或Python,构造函数是一个虚拟方法的对象代表类(这意味着你不需要GoF抽象工厂模式,可以通过代表类的对象,而不是让你自己的),c++是一种基于类的语言,和没有对象代表的任何语言的结构。类在运行时不作为对象存在,因此不能在其上调用虚拟方法。

This fits with the 'you don't pay for what you don't use' philosophy, though every large C++ project I've seen has ended up implementing some form of abstract factory or reflection.

这符合“不花钱买不使用的东西”的理念,尽管我看到的每个大型c++项目最终都实现了某种形式的抽象工厂或反射。

#4


35  

two reasons I can think of:

我可以想到两个原因:

Technical reason

技术原因

The object exists only after the constructor ends.In order for the constructor to be dispatched using the virtual table , there has to be an existing object with a pointer to the virtual table , but how can a pointer to the virtual table exist if the object still doesn't exist? :)

对象仅在构造函数结束后才存在。为了使用虚拟表分派构造函数,必须有一个具有指向虚拟表的指针的现有对象,但是如果对象仍然不存在,那么指向虚拟表的指针又如何存在呢?:)

Logic reason

逻辑的原因

You use the virtual keyword when you want to declare a somewhat polymorphic behaviour. But there is nothing polymorphic with constructors , constructors job in C++ is to simply put an object data on the memory . Since virtual tables (and polymorphism in general) are all about polymorphic behaviour rather on polymorphic data , There is no sense with declaring a virtual constructor.

当您想要声明某种多态行为时,您可以使用虚拟关键字。但是对于构造函数来说没有什么多态性,在c++中构造函数的工作就是把对象数据放在内存中。由于虚拟表(以及通常的多态性)都是关于多态性行为,而不是关于多态性数据,因此声明虚拟构造函数是没有意义的。

#5


11  

We do, it's just not a constructor :-)

是的,它不是构造函数

struct A {
  virtual ~A() {}
  virtual A * Clone() { return new A; }
};

struct B : public A {
  virtual A * Clone() { return new B; }
};

int main() {

   A * a1 = new B;
   A * a2 = a1->Clone();    // virtual construction
   delete a2;
   delete a1;
}

#6


11  

Semantic reasons aside, there is no vtable until after the object is constructed, thus making a virtual designation useless.

除了语义上的原因,在对象被构造之后才会有vtable,因此虚拟指定是无用的。

#7


8  

Summary: the C++ Standard could specify a notation and behaviour for "virtual constructor"s that's reasonably intuitive and not too hard for compilers to support, but why make a Standard change for this specifically when the functionality can already be cleanly implemented using create() / clone() (see below)? It's not nearly as useful as many other language proposal in the pipeline.

概述:c++标准可以为“虚拟构造函数”指定一种符号和行为,这种符号和行为是相当直观的,编译器不太难以支持,但是为什么要为此做一个标准更改呢?它远不如许多其他语言提案有用。

Discussion

Let's postulate a "virtual constructor" mechanism:

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

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

In the above, the first line constructs a Derived object, so *p's virtual dispatch table can reasonably supply a "virtual constructor" for use in the second line. (Dozens of answers on this page stating "the object doesn't yet exist so virtual construction is impossible" are unnecessarily myopically focused on the to-be-constructed object.)

在上面,第一行构造了一个派生对象,因此*p的虚拟分派表可以合理地提供一个“虚拟构造函数”用于第二行。(在这个页面上,有几十个答案说明“这个对象还不存在,所以虚拟构建是不可能的”,这是不必要地把注意力集中在将要构建的对象上。)

The second line postulates the notation new p->Base() to request dynamic allocation and default construction of another Derived object.

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

Notes:

注:

  • 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

      p->Base()构造的对象的大小通常不能在编译时被知道,所以动态分配是唯一有意义的方法

      • 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)
      • 可以在堆栈上分配运行时指定的内存数量——例如GCC的可变长度数组扩展alloca()——但是会导致显著的低效和复杂性(例如这里和这里)
  • 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.

    假定的表示法明确列出了强调动态分配和指针结果类型的新内容。

The compiler would need to:

编译器将需要:

  • find out how much memory Derived needed, either by calling an implicit virtual sizeof function or having such information available via RTTI
  • 通过调用隐式虚拟sizeof函数或通过RTTI获得此类信息,找出需要多少内存
  • call operator new(size_t) to allocate memory
  • 调用操作符new(size_t)来分配内存
  • invoke Derived() with placement new.
  • 使用新的位置调用派生()。

OR

  • create an extra vtable entry for a function that combines dynamic allocation and construction
  • 为一个结合动态分配和构造的函数创建一个额外的vtable条目。

So - it doesn't seem insurmountable to specify and implement virtual constructors, but the million-dollar question is: how would it be better than what's possible using existing C++ language features...? Personally, I see no benefit over the solution below.

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


`clone()` and `create()`

The C++ FAQ documents a "virtual constructor" idiom, containing virtual create() and clone() methods to default-construct or copy-construct a new dynamically-allocated object:

c++ FAQ文档中有一个“虚拟构造函数”习语,包含虚拟创建()和克隆()方法,用于默认构造或复制构造一个新的动态分配的对象:

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(); }

It's also possible to change or overload create() to accept arguments, though to match the base class / interface's virtual function signature, arguments to overrides must exactly match one of the base class overloads. With these explicit user-provided facilities, it's easy to add logging, instrumentation, alter memory allocation etc..

也可以更改或重载create()来接受参数,但是要匹配基类/接口的虚函数签名,重写的参数必须与基类重载中的一个完全匹配。有了这些明确的用户提供的工具,很容易添加日志记录、插装、修改内存分配等。

#8


3  

Although the concept of virtual constructors does not fit in well since object type is pre-requisite for object creation, its not completly over-ruled.

虽然虚拟构造函数的概念并不适合,因为对象类型是创建对象的先决条件,但它并没有完全被过度控制。

GOF's 'factory method' design pattern makes use of the 'concept' of virtual constructor, which is handly in certain design situations.

GOF的“工厂方法”设计模式利用了虚拟构造函数的“概念”,在某些设计情况下非常方便。

#9


3  

Virtual functions are used in order to invoke functions based on the type of object pointed to by the pointer, and not the type of pointer itself. But a constructor is not "invoked". It is called only once when an object is declared. So, a constructor cannot be made virtual in C++.

虚函数用于根据指针指向的对象类型而不是指针本身的类型调用函数。但是构造函数不会被“调用”。当一个对象被声明时,它只被调用一次。因此,构造函数不能在c++中成为虚拟的。

#10


2  

You shouldn't call virtual function within your constructor either. See : http://www.artima.com/cppsource/nevercall.html

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

In addition I'm not sure that you really need a virtual constructor. You can achieve polymorphic construction without it: you can write a function that will construct your object according to the needed parameters.

此外,我不确定您是否真的需要一个虚拟构造函数。您可以不使用它来实现多态结构:您可以编写一个函数,根据需要的参数来构造对象。

#11


2  

When people ask a question like this, I like to think to myself "what would happen if this were actually possible?" I don't really know what this would mean, but I guess it would have something to do with being able to override the constructor implementation based on the dynamic type of the object being created.

当人们问这样的问题时,我喜欢对自己说“如果这是可能的,会发生什么?”我不知道这意味着什么,但我想这可能与能够基于创建的对象的动态类型重写构造函数实现有关。

I see a number of potential problems with this. For one thing, the derived class will not be fully constructed at the time the virtual constructor is called, so there are potential issues with the implementation.

我看到了一些潜在的问题。首先,在调用虚拟构造函数时,派生类不会被完全构造,因此实现中存在潜在的问题。

Secondly, what would happen in the case of multiple inheritance? Your virtual constructor would be called multiple times presumably, you would then need to have some way of know which one was being called.

第二,在多重继承的情况下会发生什么?您的虚拟构造函数可能会被多次调用,因此您需要有一些方法来知道调用了哪一个。

Thirdly, generally speaking at the time of construction, the object does not have the virtual table fully constructed, this means it would require a large change to the language specification to allow for the fact that the dynamic type of the object would be known at construction time. This would then allow the base class constructor to maybe call other virtual functions at construction time, with a not fully constructed dynamic class type.

第三,一般来说,在构建时,对象没有完整地构造虚拟表,这意味着需要对语言规范进行较大的更改,以允许在构建时了解对象的动态类型。然后,这将允许基类构造函数在构建时调用其他虚拟函数,并使用未完全构造的动态类类型。

Finally, as someone else has pointed out you can implement a kind of virtual constructor using static "create" or "init" type functions that basically do the same thing as a virtual constructor would do.

最后,正如其他人指出的那样,您可以使用静态的“创建”或“init”类型函数实现一种虚拟构造函数,这些函数基本上与虚拟构造函数所做的事情相同。

#12


2  

Virtual functions in C++ are an implementation of run-time polymorphism, and they will do function overriding. Generally the virtual keyword is used in C++ when you need dynamic behavior. It will work only when object exists. Whereas constructors are used to create the objects. Constructors will be called at the time of object creation.

c++中的虚函数是运行时多态性的实现,它们将执行函数覆盖。通常,当您需要动态行为时,在c++中使用virtual关键字。只有对象存在时,它才会工作。而构造函数用于创建对象。在创建对象时将调用构造函数。

So if you create the constructor as virtual, as per the virtual keyword definition, it should have existing object to use, but constructor is used to to create the object, so this case will never exist. So you should not use the constructor as virtual.

因此,如果按照virtual关键字定义将构造函数创建为virtual,则应该使用已有的对象,但是使用构造函数来创建对象,因此这种情况永远不会存在。因此,不应该将构造函数用作虚函数。

So, if we try to declare virtual constructor compiler throw an Error:

因此,如果我们试图声明虚拟构造函数编译器抛出一个错误:

Constructors cannot be declared virtual

构造函数不能声明为虚

#13


2  

You can find an example and the technical reason to why it is not allowed in @stefan 's answer. Now a logical answer to this question according to me is:

你可以在@stefan的回答中找到一个例子和技术原因。对于这个问题,我有一个合理的答案:

The major use of virtual keyword is to enable polymorphic behaviour when we don't know what type of the object the base class pointer will point to.

virtual关键字的主要用途是在我们不知道基类指针指向的对象的类型时启用多态行为。

But think of this is more primitive way, for using virtual functionality you will require a pointer. And what does a pointer require? An object to point to! (considering case for correct execution of the program)

但这是一种更原始的方式,对于使用虚拟功能,您将需要一个指针。指针需要什么?一个指向的对象!(考虑正确执行程序的情况)

So, we basically require an object that already exists somewhere in the memory (we are not concerned with how the memory was allocated, it may be at compile time or either runtime) so that our pointer can correctly point to that object.

因此,我们基本上需要一个已经存在于内存中的对象(我们不关心内存是如何分配的,它可能在编译时或者运行时),这样我们的指针就可以正确地指向那个对象。

Now, think of the situation about the moment when the object of the class to be pointed is being assigned some memory -> Its constructor will be called automatically at that instance itself!

现在,考虑一下当类的对象被分配到某个内存时,它的构造函数会自动被调用到那个实例本身!

So we can see that we don't actually need to worry about the constructor being virtual, because in any of the cases you wish to use a polymorphic behaviour our constructor would have already been executed making our object ready for usage!

因此,我们可以看到,我们实际上并不需要担心构造函数是虚拟的,因为在任何情况下,您希望使用多态行为,我们的构造函数就已经执行了,使我们的对象可以随时使用!

#14


1  

The virtual mechanism only works when you have a based class pointer to a derived class object. Construction has it's own rules for the calling of base class constructors, basically base class to derived. How could a virtual constructor be useful or called? I don't know what other languages do, but I can't see how a virtual constructor could be useful or even implemented. Construction needs to have taken place for the virtual mechanism to make any sense and construction also needs to have taken place for the vtable structures to have been created which provides the mechanics of the polymorphic behaviour.

虚拟机制只在具有到派生类对象的基于类指针时才工作。构造有它自己的调用基类构造函数的规则,基本是基类派生的规则。虚拟构造函数如何有用或调用?我不知道其他语言做什么,但我看不出虚拟构造函数是如何有用的,甚至是如何实现的。为了使虚拟机制变得有意义,需要进行构建,并且还需要构建vtable结构,以提供多态性行为的机制。

#15


1  

Cant we simply say it like.. We cannot inherit constructors. So there is no point declaring them virtual because the virtual provides polymorphism .

我们不能就这么说吗我们不能继承的构造函数。因此,没有必要将它们声明为虚,因为虚提供了多态性。

#16


1  

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.

一个虚拟表(vtable)是为每个拥有一个或多个“虚拟函数”的类而创建的。每当创建此类对象时,它都包含一个指向相应vtable基础的“虚拟指针”。只要有虚函数调用,就使用vtable解析函数地址。构造函数不能是虚拟的,因为当一个类的构造函数被执行时,在内存中没有vtable,意味着没有定义的虚拟指针。因此构造函数应该始终是非虚的。

#17


0  

C++ virtual constructor is not possible.For example you can not mark a constructor as virtual.Try this code

不可能使用c++虚拟构造函数。例如,不能将构造函数标记为虚。试试这个代码

#include<iostream.h>
using namespace std;
class aClass
{
    public:
        virtual aClass()
        {   
        }  
};
int main()
{
    aClass a; 
}

It causes an error.This code is trying to declare a constructor as virtual. Now let us try to understand why we use virtual keyword. Virtual keyword is used to provide run time polymorphism. For example try this code.

它会导致一个错误。这段代码试图将构造函数声明为虚拟的。现在让我们尝试理解为什么我们使用virtual关键字。Virtual关键字用于提供运行时多态性。例如,试试这段代码。

#include<iostream.h>
using namespace std;
class aClass
{
    public:
        aClass()
        {
            cout<<"aClass contructor\n";
        }
        ~aClass()
        {
            cout<<"aClass destructor\n";
        }

};
class anotherClass:public aClass
{

    public:
        anotherClass()
        {
            cout<<"anotherClass Constructor\n";
        }
        ~anotherClass()
        {
            cout<<"anotherClass destructor\n";
        }

};
int main()
{
    aClass* a;
    a=new anotherClass;
    delete a;   
    getchar(); 
}

In main a=new anotherClass; allocates a memory for anotherClass in a pointer a declared as type of aClass.This causes both the constructor (In aClass and anotherClass) to call automatically.So we do not need to mark constructor as virtual.Because when an object is created it must follow the chain of creation (i.e first the base and then the derived classes). But when we try to delete a delete a; it causes to call only the base destructor.So we have to handle the destructor using virtual keyword. So virtual constructor is not possible but virtual destructor is.Thanks

在主= new anotherClass;在一个被声明为aClass类型的指针中为另一个类分配一个内存。这会导致构造函数(在aClass和其他类中)自动调用。因此,我们不需要将构造函数标记为virtual。因为当一个对象被创建时,它必须遵循创建链(i)。首先是基础,然后是派生类。但是当我们试图删除一个删除的时候;它只调用基析构函数。所以我们必须使用virtual关键字来处理析构函数。所以虚拟构造函数是不可能的但是虚拟析构函数是。谢谢

#18


0  

There's a very basic reason: Constructors are effectively static functions, and in C++ no static function can be virtual.

有一个非常基本的原因:构造函数实际上是静态函数,在c++中没有静态函数可以是虚函数。

If you have much experience with C++, you know all about the difference between static & member functions. Static functions are associated with the CLASS, not the objects (instances), so they don't see a "this" pointer. Only member functions can be virtual, because the vtable- the hidden table of function pointers that makes 'virtual' work- is really a data member of each object.

如果您有很多c++的经验,您就会了解静态函数和成员函数之间的差异。静态函数与类相关联,而不是对象(实例),因此它们不会看到“this”指针。只有成员函数可以是虚的,因为vtable——使“虚”工作的函数指针的隐藏表——实际上是每个对象的数据成员。

Now, what is the constructor's job? It is in the name- a "T" constructor initializes T objects as they're allocated. This automatically precludes it being a member function! An object has to EXIST before it has a "this" pointer and thus a vtable. That means that even if the language treated constructors as ordinary functions (it doesn't, for related reasons I won't get into), they'd have to be static member functions.

构造函数的工作是什么?它在名称中——“T”构造函数在分配T对象时初始化它们。这自动排除了它是一个成员函数!一个对象必须在有一个“this”指针和一个vtable之前存在。这意味着,即使语言将构造函数视为普通函数(出于相关原因,我不会深入讨论),它们也必须是静态成员函数。

A great way to see this is to look at the "Factory" pattern, especially factory functions. They do what you're after, and you'll notice that if class T has a factory method, it is ALWAYS STATIC. It has to be.

查看这一点的一个好方法是查看“工厂”模式,特别是工厂功能。它们做你想做的,你会注意到如果类T有一个工厂方法,它总是静态的。它必须是。

#19


-1  

The Vpointer is created at the time of object creation. vpointer wont exists before object creation. so there is no point of making the constructor as virtual.

Vpointer是在创建对象时创建的。在创建对象之前,vpointer不存在。因此,将构造函数设为虚函数是毫无意义的。

#20


-1  

If you think logically about how constructors work and what the meaning/usage of a virtual function is in C++ then you will realise that a virtual constructor would be meaningless in C++. Declaring something virtual in C++ means that it can be overridden by a sub-class of the current class, however the constructor is called when the objected is created, at that time you cannot be creating a sub-class of the class, you must be creating the class so there would never be any need to declare a constructor virtual.

如果您逻辑地思考构造函数的工作方式,以及在c++中虚拟函数的含义/用法,那么您将认识到,在c++中虚拟构造函数是没有意义的。在c++中声明一些虚拟意味着它可以覆盖当前类的子类,但是调用构造函数创建反对时,那时你不能创建一个类的子类,您必须创建类所以不会有任何需要声明一个构造函数的虚拟。

And another reason is, the constructors have the same name as its class name and if we declare constructor as virtual, then it should be redefined in its derived class with the same name, but you can not have the same name of two classes. So it is not possible to have a virtual constructor.

另一个原因是,构造函数的名称与其类名相同,如果我们将构造函数声明为virtual,那么它应该在它的派生类中以相同的名称重新定义,但是两个类的名称不能相同。所以不可能有一个虚拟构造函数。