为什么c++没有虚构造函数?
当前回答
“构造函数不能是虚拟的”
有一些合理的理由可以证明这种说法是正确的。
要创建对象,对象类的构造函数必须与类的类型相同。但是,对于虚拟实现的构造函数,这是不可能的。 在调用构造函数时,还没有创建虚表来解析任何虚函数调用。因此,虚拟构造函数本身将没有任何可以查找的地方。
因此,不可能将构造函数声明为虚函数。
其他回答
c++的虚拟构造函数是不可能的。例如,不能将构造函数标记为虚函数。试试这段代码
#include<iostream.h>
using namespace std;
class aClass
{
public:
virtual aClass()
{
}
};
int main()
{
aClass a;
}
它会导致错误。这段代码试图将构造函数声明为虚函数。 现在让我们试着理解为什么要使用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
与面向对象的语言(如Smalltalk或Python)不同,这些语言的构造函数是表示类的对象的虚拟方法(这意味着您不需要GoF抽象工厂模式,因为您可以传递表示类的对象,而不是自己创建),c++是一种基于类的语言,并且没有表示语言的任何构造的对象。该类在运行时不作为对象存在,因此不能对其调用虚方法。
这符合“不用就不用付钱”的理念,尽管我所见过的每个大型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()以接受参数,不过为了匹配基类/接口的虚函数签名,重写的参数必须精确匹配基类重载中的一个。有了这些用户提供的显式功能,添加日志记录、检测、更改内存分配等就变得很容易了。
在创建对象时创建Vpointer。创建对象前Vpointer不存在。因此,没有必要将构造函数设为虚函数。
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.