为什么我们在 C++ 中没有虚拟构造函数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/733360/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why do we not have a virtual constructor in C++?
提问by Arjun
Why does C++ not have a virtual constructor?
为什么 C++ 没有虚拟构造函数?
回答by aJ.
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++ Style and Technique FAQ为什么我们没有虚拟构造函数?
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.
虚拟调用是一种在给定部分信息的情况下完成工作的机制。特别是,“虚拟”允许我们调用一个只知道任何接口而不是对象的确切类型的函数。要创建对象,您需要完整的信息。特别是,您需要知道要创建的确切类型。因此,“对构造函数的调用”不能是虚拟的。
The FAQ entry goes on to give the code for a way to achieve this end without a virtual constructor.
FAQ 条目继续提供了一种无需虚拟构造函数即可实现此目的的方法的代码。
回答by Anton Gogolev
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 actualtype 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))
回答by Pete Kirkham
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++ 项目最终都实现了某种形式的抽象工厂或反射。
回答by user88637
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.
当您想声明某种多态行为时,您可以使用 virtual 关键字。但是构造函数没有多态性,C++ 中的构造函数的工作就是简单地将对象数据放在内存中。由于虚拟表(以及一般的多态性)都是关于多态行为而不是多态数据,因此声明虚拟构造函数是没有意义的。
回答by Tony Delroy
Summary: the C++ Standard couldspecify 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 functionalitycan already be cleanly implemented using create()
/ clone()
(see below)? It's not nearly as useful as many other language proposal in the pipeline.
总结:C++ 标准可以为“虚拟构造函数”指定一个相当直观的符号和行为,编译器支持它并不太难,但是当功能已经可以使用create()
/干净地实现时,为什么要为此进行标准更改clone()
(请参阅以下)?它不像管道中的许多其他语言提案那么有用。
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.)
在上面,第一行构造了一个Derived
对象,所以*p
的虚拟调度表可以合理地提供一个“虚拟构造函数”供第二行使用。(此页面上的数十个答案表明“该对象尚不存在,因此无法进行虚拟构建”,这不必要地短视地将注意力集中在要构建的对象上。)
The second line postulates the notation new p->Base()
to request dynamic allocation and default construction of another Derived
object.
第二行假定符号new p->Base()
请求动态分配和另一个Derived
对象的默认构造。
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 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. hereand hererespectively)
- it is possible to allocate runtime-specified amounts of memory on the stack - e.g. GCC's variable-length array extension,
for dynamic allocation it mustreturn a pointer so memory can be
delete
d later.the postulated notation explicitly lists
new
to emphasise dynamic allocation and the pointer result type.
编译器必须在调用构造函数之前编排内存分配- 构造函数通常支持自动(非正式的“堆栈”)分配、静态(对于全局/命名空间范围和类/函数
static
对象)和动态(非正式的“堆”)new
使用时p->Base()
在编译时通常无法知道要构造的对象的大小,因此动态分配是唯一有意义的方法- 能够分配在栈上运行时指定量的存储器-例如,GCC的可变长度阵列延伸,
alloca()
-但导致低效率显著和复杂性(例如,在这里和在这里分别)
- 能够分配在栈上运行时指定量的存储器-例如,GCC的可变长度阵列延伸,
对于动态分配,它必须返回一个指针,以便
delete
稍后可以使用内存。假定的符号明确列出
new
以强调动态分配和指针结果类型。
The compiler would need to:
编译器需要:
- find out how much memory
Derived
needed, either by calling an implicitvirtual
sizeof
function or having such information available via RTTI - call
operator new(size_t)
to allocate memory - invoke
Derived()
with placementnew
.
Derived
通过调用隐式virtual
sizeof
函数或通过 RTTI 获取此类信息,找出需要多少内存- 调用
operator new(size_t)
分配内存 Derived()
使用放置调用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()`
`clone()` 和 `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文档的“虚拟构造函数”成语,含有virtual
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(); }
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()
以接受参数,但要匹配基类/接口的virtual
函数签名,覆盖的参数必须与基类重载之一完全匹配。使用这些由用户提供的显式工具,可以轻松添加日志记录、检测、更改内存分配等。
回答by Marius
Semantic reasons aside, there is no vtable until after the object is constructed, thus making a virtual designation useless.
撇开语义原因不谈,在构造对象之前没有 vtable,因此虚拟指定毫无用处。
回答by Marius
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;
}
回答by Neha kumari
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++ 中的虚函数是运行时多态的实现,它们会覆盖函数。virtual
当您需要动态行为时,通常在 C++ 中使用关键字。只有当对象存在时它才会起作用。而构造函数用于创建对象。构造函数将在对象创建时调用。
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.
因此,如果您将构造函数创建为 as virtual
,根据 virtual 关键字定义,它应该具有要使用的现有对象,但是构造函数用于创建对象,因此这种情况永远不会存在。所以你不应该将构造函数用作虚拟的。
So, if we try to declare virtual constructor compiler throw an Error:
所以,如果我们尝试声明虚拟构造函数,编译器会抛出一个错误:
Constructors cannot be declared virtual
构造函数不能被声明为 virtual
回答by Kushan Mehta
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!
所以我们可以看到,我们实际上不需要担心构造函数是虚拟的,因为在任何情况下,您希望使用多态行为,我们的构造函数已经被执行,使我们的对象准备好使用!
回答by skrtbhtngr
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++ 中将构造函数设为虚拟。