为什么 C 中没有虚拟构造函数?
为什么C++没有虚拟构造函数?
Why does C++ not have a virtual constructor?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
为什么C++没有虚拟构造函数?
Why does C++ not have a virtual constructor?
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(23)
从马口中听到的。 :)
来自 Bjarne Stroustrup 的 C++ 风格和技术常见问题解答 为什么我们没有虚拟构造函数?
常见问题解答条目继续提供了无需虚拟构造函数即可实现此目的的方法的代码。
Hear it from the horse's mouth. :)
From Bjarne Stroustrup's C++ Style and Technique FAQ Why don't we have virtual constructors?
The FAQ entry goes on to give the code for a way to achieve this end without a virtual constructor.
虚函数基本上提供了多态行为。 也就是说,当您使用动态类型与引用它的静态(编译时)类型不同的对象时,它提供适合对象的实际类型的行为,而不是对象的静态类型。
现在尝试将这种行为应用于构造函数。 当您构造对象时,静态类型始终与实际对象类型相同,因为:
(Bjarne Stroustup(P424 C++ 编程语言 SE))
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:
(Bjarne Stroustup (P424 The C++ Programming Language SE))
与 Smalltalk 或 Python 等面向对象语言不同,构造函数是代表类的对象的虚拟方法(这意味着您不需要 GoF 抽象工厂模式,因为您可以传递代表类的对象而不是创建自己的对象),C++ 是基于类的语言,并且没有代表该语言的任何对象的对象结构体。 该类在运行时并不作为对象存在,因此您无法对其调用虚拟方法。
这符合“你不用为不使用的东西付费”的理念,尽管我见过的每个大型 C++ 项目最终都实现了某种形式的抽象工厂或反射。
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.
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.
我能想到的两个原因:
技术原因
该对象仅在构造函数结束后才存在。为了使用虚拟表分派构造函数,必须存在一个带有指向虚拟表的指针的现有对象,但是如何才能如果对象还不存在,指向虚拟表的指针是否存在? :)
逻辑原因
当您想要声明某种程度的多态行为时,可以使用 virtual 关键字。 但是构造函数不存在多态性,C++ 中的构造函数的工作就是简单地将对象数据放入内存中。 由于虚拟表(以及一般的多态性)都是关于多态行为而不是多态数据,因此声明虚拟构造函数是没有意义的。
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++ 标准可以为“虚拟构造函数”指定一种相当直观的表示法和行为,并且对于编译器来说支持也不太难,但是,当已经可以使用
create()
/clone()
干净地实现功能时,为什么要为此进行标准更改(见下文) ? 它并不像管道中的许多其他语言提案那么有用。讨论
让我们假设一个“虚拟构造函数”机制:
在上面,第一行构造了一个
Derived
对象,因此*p
的虚拟调度表可以合理地提供一个“虚拟构造函数”。构造函数”用于第二行。 (本页上的数十个答案都指出“该对象尚不存在,因此虚拟构造是不可能的”,这些答案不必要地短视地集中在要构造的对象上。)第二行假设了符号 < code>new p->Base() 请求动态分配和默认构造另一个
Derived
对象。注意:
编译器必须在调用构造函数之前协调内存分配 - 构造函数通常支持自动(非正式的“堆栈”)分配,< em>static(对于全局/命名空间范围和类/函数
static
对象),以及new时的动态(非正式的“堆”)使用
p->Base()
构造的对象的大小通常无法在编译时得知,因此动态分配是唯一有意义的方法alloca()
- 但会导致显着的低效率和复杂性(例如 此处和此处分别)对于动态分配,它必须返回一个指针,以便稍后可以
删除
内存。假定的符号显式列出
new
以强调动态分配和指针结果类型。编译器需要:
virtual
sizeof
函数或通过 RTTI 获取此类信息,找出需要多少Derived
内存operator new(size_t)
来分配内存Derived()
并放置new
。或者
所以 - 指定和实现虚拟构造函数似乎并不是不可克服的,但价值百万美元的问题是:它如何比使用现有 C++ 语言可能更好特征...? 就我个人而言,我认为下面的解决方案没有任何好处。
`clone()` 和 `create()`
C++ FAQ 记录了“虚拟构造函数”习惯用法,包含
virtual
create()
和clone()
方法来默认构造或复制构造新的动态分配对象:不过,也可以更改或重载
create()
以接受参数为了匹配基类/接口的虚拟函数签名,重写的参数必须与基类重载之一完全匹配。 通过这些明确的用户提供的设施,可以轻松添加日志记录、检测、更改内存分配等。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.Discussion
Let's postulate a "virtual constructor" mechanism:
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.)The second line postulates the notation
new p->Base()
to request dynamic allocation and default construction of anotherDerived
object.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") whennew
is usedthe 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 sensealloca()
- 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
delete
d later.the postulated notation explicitly lists
new
to emphasise dynamic allocation and the pointer result type.The compiler would need to:
Derived
needed, either by calling an implicitvirtual
sizeof
function or having such information available via RTTIoperator new(size_t)
to allocate memoryDerived()
with placementnew
.OR
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.
`clone()` and `create()`
The C++ FAQ documents a "virtual constructor" idiom, containing
virtual
create()
andclone()
methods to default-construct or copy-construct a new dynamically-allocated object:It's also possible to change or overload
create()
to accept arguments, though to match the base class / interface'svirtual
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..我们知道,它只是不是构造函数:-)
We do, it's just not a constructor :-)
撇开语义原因不谈,在构造对象之前没有 vtable,因此虚拟指定毫无用处。
Semantic reasons aside, there is no vtable until after the object is constructed, thus making a virtual designation useless.
C++中的虚函数是运行时多态性的一种实现,它们会进行函数重写。 通常,当您需要动态行为时,C++ 中会使用
virtual
关键字。 仅当对象存在时才会起作用。 而构造函数用于创建对象。 构造函数将在对象创建时被调用。因此,如果您将构造函数创建为
virtual
,根据 virtual 关键字定义,它应该有现有的对象可供使用,但构造函数用于创建对象,因此这种情况永远不会存在。 所以你不应该将构造函数用作虚拟的。因此,如果我们尝试声明虚拟构造函数,编译器会抛出错误:
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.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.So, if we try to declare virtual constructor compiler throw an Error:
您可以在 @stefan 的答案中找到一个示例以及为什么不允许这样做的技术原因。 现在,根据我的说法,这个问题的一个合乎逻辑的答案是:
virtual 关键字的主要用途是当我们不知道基类指针将指向什么类型的对象时启用多态行为。
但认为这是更原始的方式,为了使用虚拟功能,您将需要一个指针。 指针需要什么? 一个要指向的对象! (考虑程序正确执行的情况)
因此,我们基本上需要一个已经存在于内存中某处的对象(我们不关心内存是如何分配的,它可能是在编译时或运行时),以便我们的指针可以正确指向该对象。
现在,考虑一下当要指向的类的对象被分配一些内存时的情况-> 它的构造函数将在该实例本身被自动调用!
所以我们可以看到,我们实际上不需要担心构造函数是虚拟的,因为在任何您希望使用多态行为的情况下,我们的构造函数都已经被执行,使我们的对象准备好使用!
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:
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.
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!
当人们问这样的问题时,我喜欢对自己思考“如果这实际上是可能的,会发生什么?” 我真的不知道这意味着什么,但我想这与能够根据所创建的对象的动态类型重写构造函数实现有关。
我发现这有很多潜在的问题。 一方面,派生类在调用虚拟构造函数时不会完全构造,因此实现存在潜在问题。
其次,如果多重继承会发生什么? 您的虚拟构造函数可能会被多次调用,然后您需要通过某种方式知道正在调用哪个构造函数。
第三,一般来说,在构造时,对象没有完全构造的虚拟表,这意味着需要对语言规范进行大量更改,以允许在构造时知道对象的动态类型。时间。 然后,这将允许基类构造函数在构造时使用未完全构造的动态类类型调用其他虚拟函数。
最后,正如其他人指出的那样,您可以使用静态“create”或“init”类型函数来实现一种虚拟构造函数,这些函数基本上与虚拟构造函数执行相同的操作。
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.
尽管虚拟构造函数的概念不太适合,因为对象类型是对象创建的先决条件,但它并没有完全被推翻。
GOF的“工厂方法”设计模式利用了虚拟构造函数的“概念”,这在某些设计情况下很方便。
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.
使用虚函数是为了根据指针指向的对象类型而不是指针本身的类型来调用函数。 但构造函数并没有被“调用”。 它仅在声明对象时调用一次。 因此,C++ 中的构造函数不能设为虚拟。
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++.
面试答案是:virtual ptr 和 table 与对象相关,但与类无关。因此构造函数构建虚拟表
因此我们不能有虚拟构造函数,因为在 obj 创建之前没有 Vtable。
Interview answer is : virtual ptr and table are related to objects but not the class.hence constructor builds the virtual table
hence we cant have virtual constructor as there is no Vtable before obj creation.
您也不应该在构造函数中调用虚函数。 请参阅:http://www.artima.com/cppsource/nevercall.html
中另外我不确定你是否真的需要一个虚拟构造函数。 没有它你也可以实现多态构造:你可以编写一个函数来根据所需的参数构造你的对象。
You shouldn't call virtual function within your constructor either. See : 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.
为每个具有一个或多个“虚拟函数”的类创建一个虚拟表(vtable)。 每当创建此类的对象时,它都会包含一个指向相应 vtable 基址的“虚拟指针”。 每当有虚函数调用时,都会使用 vtable 来解析函数地址。
构造函数不能是virtual,因为类的构造函数执行时内存中没有vtable,意味着还没有定义虚拟指针。 因此,构造函数应该始终是非虚拟的。
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.
我们不能简单地说...我们不能继承构造函数。 因此,将它们声明为虚拟是没有意义的,因为虚拟提供了多态性。
Cant we simply say it like.. We cannot inherit constructors. So there is no point declaring them virtual because the virtual provides polymorphism .
仅当您有指向派生类对象的基类指针时,虚拟机制才起作用。 构造函数对于基类构造函数的调用有自己的规则,基本上是从基类到派生类。 虚拟构造函数如何有用或如何被调用? 我不知道其他语言是做什么的,但我看不出虚拟构造函数如何有用,甚至如何实现。 需要进行构造才能使虚拟机制有意义,并且还需要进行构造才能创建提供多态行为机制的 vtable 结构。
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.
C++ 虚拟构造函数是不可能的。例如,您不能将构造函数标记为虚拟。尝试此代码
它会导致错误。此代码试图将构造函数声明为虚拟。
现在让我们尝试理解为什么使用 virtual 关键字。 virtual关键字用于提供运行时多态性。 例如尝试这个代码。
在 main 中,
a=new anotherClass;
在声明为aClass
类型的指针a
中为anotherClass
分配内存。这会导致构造函数(在aClass
和anotherClass
中)自动调用。所以我们不需要将构造函数标记为virtual。因为当创建一个对象时,它必须遵循创建链(即首先是基类,然后是派生类)。但是当我们尝试删除一个
delete a;
时,它会导致只调用基析构函数。所以我们必须使用 virtual 关键字来处理析构函数。 所以虚拟构造函数是不可能的,但虚拟析构函数是可能的。谢谢C++ virtual constructor is not possible.For example you can not mark a constructor as virtual.Try this code
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.
In main
a=new anotherClass;
allocates a memory foranotherClass
in a pointera
declared as type ofaClass
.This causes both the constructor (InaClass
andanotherClass
) 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有一个非常基本的原因:构造函数实际上是静态函数,并且在 C++ 中静态函数不能是虚拟的。
如果您有丰富的 C++ 经验,您就会知道 static 和 static 之间的区别。 成员函数。 静态函数与类相关联,而不是与对象(实例)相关联,因此它们看不到“this”指针。 只有成员函数可以是虚拟的,因为 vtable(使“虚拟”工作的函数指针的隐藏表)实际上是每个对象的数据成员。
现在,建造者的工作是什么? 它就在名称中——“T”构造函数在分配 T 对象时初始化它们。 这会自动排除它作为成员函数! 一个对象在拥有“this”指针和虚函数表之前必须存在。 这意味着即使该语言将构造函数视为普通函数(事实并非如此,由于相关原因我不会深入讨论),它们也必须是静态成员函数。
了解这一点的一个好方法是查看“工厂”模式,尤其是工厂函数。 他们做你想做的事,你会注意到,如果类 T 有一个工厂方法,它总是静态的。 它一定要是。
There's a very basic reason: Constructors are effectively static functions, and in C++ no static function can be virtual.
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.
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.
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.
如果您逻辑地思考构造函数如何工作以及虚函数在 C++ 中的含义/用法是什么,那么您将意识到虚构造函数在 C++ 中毫无意义。 在C++中声明虚拟的东西意味着它可以被当前类的子类覆盖,但是当创建对象时会调用构造函数,此时你不能创建该类的子类,你必须创建该类,因此永远不需要将构造函数声明为虚拟的。
另一个原因是,构造函数与其类名具有相同的名称,如果我们将构造函数声明为virtual,那么它应该在其派生类中以相同的名称重新定义,但两个类不能具有相同的名称。 所以不可能有虚拟构造函数。
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.
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.
当调用构造函数时,虽然到目前为止还没有创建对象,但我们仍然知道将要创建的对象类型,因为对象所属类的特定构造函数 to 已经被调用。
与函数关联的
Virtual
关键字意味着将调用特定对象类型的函数。所以,我的想法是没有必要创建虚拟构造函数,因为已经调用了要创建对象的所需构造函数,并且使构造函数成为虚拟函数只是一件多余的事情,因为对象 -特定的构造函数已经被调用,这与通过 virtual 关键字调用特定于类的函数相同。
尽管由于 vptr 和 vtable 相关原因,内部实现不允许使用虚拟构造函数。
另一个原因是 C++ 是静态类型语言,我们需要知道变量的类型在编译时。
编译器必须知道类类型才能创建对象。 要创建的对象的类型是编译时决定的。
如果我们将构造函数设为虚拟,那么这意味着我们不需要在编译时知道对象的类型(这就是虚拟函数提供的。我们不需要知道实际的对象,只需要指向实际对象的基指针在不知道对象类型的情况下调用所指向对象的虚函数),如果我们在编译时不知道对象的类型,那么它就违背了静态类型语言。 因此,无法实现运行时多态性。
因此,在编译时不知道对象类型的情况下,不会调用构造函数。 因此,创建虚拟构造函数的想法失败了。
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.
“构造函数不能是虚拟的”
因此,不可能将构造函数声明为虚拟的。
"A constructor can not be virtual"
As a result, it is not possible to declare a constructor to be virtual.
Vpointer是在对象创建时创建的。 vpointer 在对象创建之前不会存在。 所以将构造函数设置为虚拟是没有意义的。
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.