27 / 163 · C++14 · 9 min
Why there is no virtual constructor: factory and clone
A constructor cannot be declared virtual. A creation expression already decides the concrete type to build; an unfinished object cannot reverse-select the constructed type. Runtime type selection should use a factory; copying according to an existing dynamic type uses a virtual clone. Virtual calls during construction also have phase restrictions.
In this lesson
The created type is determined before initialization
C++ explicitly does not allow a constructor to be virtual. The syntax that invokes construction already specifies the class that must be initialized. Space requirements and the base-class member layout must be decided by the type being created. A virtual call, by contrast, selects an implementation on an already existing object interface. The two jobs are different.
"The vtable does not exist before construction" can help explain some ABI implementation processes, but it is not the language's official basis for forbidding virtual constructors, and it cannot be used to conclude that calling virtual functions from constructors is always forbidden. When explaining the rule, first state the difference between type creation and dynamic dispatch, then add the vtable as an implementation detail.
Design runtime selection and polymorphic copying separately
If input decides which type to create, write a factory that returns unique_ptr<Base>, construct the concrete derived object in a branch, then hand ownership uniformly to the caller. If a polymorphic object already exists and you need to copy its actual derived state, define virtual unique_ptr<Base> clone() const and let the derived implementation copy itself.
clone is an ordinary virtual member function, not a true virtual constructor. It returns a new object that has already finished construction. Smart-pointer return types do not support language-level covariance, so the override declaration keeps unique_ptr<Base>. When the function body returns the result of make_unique<Derived>, it then uses the conversion that smart pointers support.
Virtual dispatch during construction stops at the current layer
When a base-class constructor calls a virtual function on the current object, it selects the final overrider of the base construction phase and will not jump to a derived layer that is not yet finished. After base initialization completes, during the derived class's own member initialization and in the constructor body, a legitimate virtual call on the current object selects that derived layer's final overrider and will not enter a more-derived layer. The call still must not read members that are not yet initialized. During destruction, dispatch likewise reaches only the layer currently being destroyed.
The example saves the result of calling kind during base construction as one, while kind on the complete object returns two, showing that this is not a failure of the virtual mechanism but a rule of the object-construction process. If a startup operation must depend on complete derived state, have the factory invoke it explicitly after successful construction, and first make the resource-cleanup semantics on failure explicit.
Pitfalls
- Do not rely on a derived override in a base constructor to initialize derived fields; the derived part is not finished yet.
- Returning a raw pointer from clone makes the ownership contract obscure; when returning an owning pointer you must also ensure the base destruction policy is correct.
Run an example
Minimum C++14 · complete program · Download .cpp
#include <cassert>
#include <memory>
class Base {
int observed_;
public:
Base() : observed_(kind()) {}
virtual int kind() const { return 1; }
int observed_during_construction() const { return observed_; }
virtual std::unique_ptr<Base> clone() const = 0;
virtual ~Base() = default;
};
class Derived final : public Base {
public:
int kind() const override { return 2; }
std::unique_ptr<Base> clone() const override {
return std::make_unique<Derived>(*this);
}
};
std::unique_ptr<Base> make_object() {
return std::make_unique<Derived>();
}
int main() {
auto object = make_object();
assert(object->observed_during_construction() == 1);
assert(object->kind() == 2);
auto copy = object->clone();
assert(copy.get() != object.get());
assert(copy->kind() == 2);
}
Compile locally
g++ -std=c++14 -Wall -Wextra -Wpedantic -pthread objects-virtual-constructor.cpp -o example && ./exampleExpected result
Expected: exit 0, no output; every assert holds.
CHECK YOUR UNDERSTANDING
Close the answer. Explain it.
If Base::kind is also made pure virtual, can you add an out-of-class definition so that the kind() call in the Base constructor is safe?
Show a reference answer
No. A pure virtual call on the object under construction is still undefined behavior; having a function body does not change the rule. You can instead call a non-virtual helper, or, when you truly need to reuse a pure virtual definition, use an explicit qualified call Base::kind(). That qualified call only executes the base definition and still will not initialize or invoke derived-layer behavior.
Check the sources
Drafts and official chapters change. The version mark is only the example’s minimum.