Why do we not have a virtual constructor in C++?

259,248

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") 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.

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
  • call operator new(size_t) to allocate memory
  • invoke Derived() with placement new.

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..

Share:
259,248

Related videos on Youtube

Arjun
Author by

Arjun

Updated on June 11, 2021

Comments

  • Arjun
    Arjun about 3 years

    Why does C++ not have a virtual constructor?

    • R Sahu
      R Sahu over 7 years
      If C++ did have virtual constructors, how would you use them?
    • gawkface
      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
      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
    Frederik Slijkerman about 15 years
    This 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
    Ankit Roy about 15 years
    I was wondering how the question even made sense until I read this explanation of how object creation works in other languages. +1.
  • Tony Lee
    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
    Tunvir Rahman Tusher about 11 years
    For virtual destructor try this link.stackoverflow.com/questions/461203/… might help
  • Afghan Host
    Afghan Host almost 11 years
    From this link: docwiki.embarcadero.com/RADStudio/XE4/en/… A use case, see: virtual __fastcall TYesNoDialog(TComponent *Owner);
  • Bình Nguyên
    Bình Nguyên almost 10 years
    so, why destructor can have virtual?
  • curiousguy
    curiousguy almost 9 years
    Constructors are not static, period.
  • curiousguy
    curiousguy almost 9 years
    Wrong. vtables are static and constant. They exist since the loading of the code and static data of the executable.
  • curiousguy
    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
    curiousguy almost 9 years
    The vptr is an implementation detail; it implements the concept of dynamic type. The ctor give a dynamic type, creates a polymorphic object.
  • David Schwartz
    David Schwartz almost 8 years
    The difference is that these clone and create 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
    David Schwartz almost 8 years
    This is obvious nonsense. A f (g); invokes a copy constructor. And there's an object it could be a member function of, g. Or void foo (A a); ... foo(f);. Here, we need to construct a new A to call foo, and look there's an object it could be a member function of -- f.
  • Tony Delroy
    Tony Delroy almost 8 years
    @DavidSchwartz: clone and create don't work directly with Standard containers, but it's trivial to write a small management type that clones 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. With clone / 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
    David Schwartz almost 8 years
    It'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
    Rayee Roded almost 7 years
    Quick search will yield the answer: stackoverflow.com/questions/461203/…
  • roottraveller
    roottraveller almost 7 years
    virtual destructor does not show polymorphic behaviour? you sure about 2nd reason?
  • Marius
    Marius over 6 years
    Correct, they are defined static and constant, but just not allocated and set up.
  • curiousguy
    curiousguy over 6 years
    They are setup at program startup.
  • Rich
    Rich over 5 years
    @curiousguy they are setup once object construction is complete and so are not available during construction.
  • curiousguy
    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
    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
    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
    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
    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
    curiousguy over 5 years
    Constructor don't have a name. They have a specific syntax which uses the name of the class.
  • kadina
    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
    axell-brendow almost 5 years
    Is it possible to force derived classes to have a constructor without arguments ?
  • ajaysinghnegi
    ajaysinghnegi almost 5 years
    If 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
    ajaysinghnegi almost 5 years
    How are vtable updated? Do they really need vptr to be updated?
  • vpalmu
    vpalmu over 3 years
    @curiousguy: A pointer to constructor makes perfect sense. If you had one it would act like placement new.
  • curiousguy
    curiousguy over 3 years
    @Joshua Then... use placement new. What's the use case?
  • Aravinda KS
    Aravinda KS about 3 years
    Constructors are not static, to get a static constructor we have to initialize static data members independently.