Why do we not have a virtual constructor in C++?
Solution 1
Hear it from the horse's mouth. :)
From Bjarne Stroustrup's C++ Style and Technique FAQ Why don't we have virtual constructors?
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.
Solution 2
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))
Solution 3
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.
Solution 4
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.
Solution 5
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:
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.)
The second line postulates the notation new p->Base()
to request dynamic allocation and default construction of another Derived
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 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)
- 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 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:
- 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
.
OR
- create an extra vtable entry for a function that combines dynamic allocation and construction
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()
and clone()
methods to default-construct or copy-construct a new dynamically-allocated object:
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..
Related videos on Youtube
Arjun
Updated on June 11, 2021Comments
-
Arjun about 3 years
Why does C++ not have a virtual constructor?
-
R Sahu over 7 yearsIf C++ did have virtual constructors, how would you use them?
-
gawkface almost 7 years
virtual functions aid in dynamic binding -> which happens at run-time -> objects are created at run-time -> objects creation requires constructor
. If this ctor was virtual, the dog would start chasing its own tail (the dog being the poor compiler :p) -
vpalmu over 3 years@RSahu: Most likely, whoever asks for a virtual constructor in C++ has the idea in their mind it's a copy constructor and it will dynamically invoke based on the argument to the copy constructor. It makes logical sense but C++ can't handle virtual dispatch via an instance that is not a pointer, nor the dynamic stack (or worse static) memory implied.
-
-
Frederik Slijkerman about 15 yearsThis is exactly the difference between construction in C++ and in a language such as Delphi, where you do have virtual constructors. Well put.
-
Ankit Roy about 15 yearsI was wondering how the question even made sense until I read this explanation of how object creation works in other languages. +1.
-
Tony Lee almost 15 years"Advanced C++" by James Coplien talks about how to implement virtual constructors in C++ (e.g., new animal("dog")). See users.rcn.com/jcoplien/Patterns/C++Idioms/… for some more information on how it's implemented
-
Tunvir Rahman Tusher about 11 yearsFor virtual destructor try this link.stackoverflow.com/questions/461203/… might help
-
Afghan Host almost 11 yearsFrom this link: docwiki.embarcadero.com/RADStudio/XE4/en/… A use case, see: virtual __fastcall TYesNoDialog(TComponent *Owner);
-
Bình Nguyên almost 10 yearsso, why destructor can have virtual?
-
curiousguy almost 9 yearsConstructors are not static, period.
-
curiousguy almost 9 yearsWrong. vtables are static and constant. They exist since the loading of the code and static data of the executable.
-
curiousguy almost 9 years"you cannot have a pointer to a constructor" A "pointer to a constructor" has as much runtime information as an empty struct, because constructors do not have names.
-
curiousguy almost 9 yearsThe vptr is an implementation detail; it implements the concept of dynamic type. The ctor give a dynamic type, creates a polymorphic object.
-
David Schwartz almost 8 yearsThe difference is that these
clone
andcreate
functions don't work with containers, don't work with pass by value, etcetera. So they don't achieve what we want -- polymorphism without slicing while preserving ordinary value semantics. -
David Schwartz almost 8 yearsThis is obvious nonsense.
A f (g);
invokes a copy constructor. And there's an object it could be a member function of,g
. Orvoid foo (A a); ... foo(f);
. Here, we need to construct a newA
to callfoo
, and look there's an object it could be a member function of --f
. -
Tony Delroy almost 8 years@DavidSchwartz:
clone
andcreate
don't work directly with Standard containers, but it's trivial to write a small management type thatclone
s from the copy constructor etc (e.g. see here). Such management objects can also be passed around by value if you find that easier than using references. Withclone
/create
private
and the management object be-friend
-ed, you can ensure consistent use. Still, it's true that that's an extra layer of complexity that may frustrate newer C++ programmers.... -
David Schwartz almost 8 yearsIt's hardly trivial. The link goes to code that's already pretty complicated, and it's not enough to even make the standard containers work. For example, there's no
operator<
. Also, since it's not part of the language, it will be very difficult to make code that uses such a thing interoperate with code that doesn't. -
Rayee Roded almost 7 yearsQuick search will yield the answer: stackoverflow.com/questions/461203/…
-
roottraveller almost 7 yearsvirtual destructor does not show polymorphic behaviour? you sure about 2nd reason?
-
Marius over 6 yearsCorrect, they are defined static and constant, but just not allocated and set up.
-
curiousguy over 6 yearsThey are setup at program startup.
-
Rich over 5 years@curiousguy they are setup once object construction is complete and so are not available during construction.
-
curiousguy over 5 years@Rich Incorrect. Vtables are static data, like code. They are never changed and are usually mapped read only, so they cannot be changed in a running program, not even during program initialization. Also, virtual functions can be called inside a constructor.
-
Rich over 5 years@curiousguy Would I be right in thinking they can't yet behave like virtual functions when called from the constructor as constructors are executed base to derived?
-
curiousguy over 5 years@Rich No. Virtual function work in constructors exactly as anywhere else. Virtual function calls are always based on the dynamic type of the object.
-
Rich over 5 years@curiousguy Ok, so one of the reason it's advised to not call a virtual function from a constructor is because the virtual function in the derived class may access variables in the derived class that haven't been initialised yet because it's constructor hasn't executed yet?
-
curiousguy over 5 years@Rich No: inside the base class ctor, a virtual call in a constructor will dynamically call the base class version, based on the dynamic type at the time: the base class. The virtual calls on the object under construction work the same whether they are in the ctor body or in any other function call by the ctor. The dynamic type of a base class subobject changes as construction of the derived class starts. You can only see that by printing
typeid(*this).name()
. -
curiousguy over 5 yearsConstructor don't have a name. They have a specific syntax which uses the name of the class.
-
kadina over 5 years"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." This is completely wrong. If that is the same case, how destructors can be virtual? We are not redefining the base destructor in derived class.
-
axell-brendow almost 5 yearsIs it possible to force derived classes to have a constructor without arguments ?
-
ajaysinghnegi almost 5 yearsIf we use a base class pointer to point to the base class object and call a virtual function using it. Then it would be late binding. But, will that be a run time polymorphism?
-
ajaysinghnegi almost 5 yearsHow are vtable updated? Do they really need vptr to be updated?
-
vpalmu over 3 years@curiousguy: A pointer to constructor makes perfect sense. If you had one it would act like placement new.
-
curiousguy over 3 years@Joshua Then... use placement new. What's the use case?
-
Aravinda KS about 3 yearsConstructors are not static, to get a static constructor we have to initialize static data members independently.