I have some arrangement of objects, and their interrelations (a kind of topology) are independent of the type of the object. I want to use the same structure and interrelations with different contained classes, subclassed from the same container class. In my container class the relations can be fully described knowing only that the contained classes are contained in a grid; no question whether the grid is populated or not. That is, the classes derived from the container must populate the grid first in their constructor, then they are ready to go. That is, I can go with an empty container and if the derived classes in their constructor populate the grid with the corresponding objects, everything works fine. However, the constructor must populate the grid to provide a reasonable functionality. If it would not be a constructor, I would make it abstract. I can leave it empty, leaving the duty to populate it in the subclasses, or I can have a method Populate() as abstract, but that should be called form the constructor. Which (or which other) method is the best?
-
3I don't understand what you're trying to do. But calling a virtual method from a constructor probably won't do what you want. (https://stackoverflow.com/questions/962132/calling-virtual-functions-inside-constructors) – Mat Jul 23 '19 at 07:35
-
2A pure virtual function `populate` would make sense if you wanted to defer population to some later point, or if you possibly wanted to repeat population at some other point of time. However, you wouldn't be able to call it from the constructor anyway, as @Mat denoted already. If you don't need such deferred or repeated population, then I'd just leave population to the child constructors. The base class might provide some (non-virtual) helper functions for this purpose (something like `void place(unsigned x, unsigned y, Base* object);`), though. – Aconcagua Jul 23 '19 at 07:43
-
@dodekja Somewhat similar, my question is about making the constructor virtual, not only the class – katang Jul 23 '19 at 07:53
-
Terminology: an **abstract class** is a class that has one or more **pure virtual** functions. So, literally, no, a constructor cannot be "abstract" because it's not a class. – Pete Becker Jul 23 '19 at 13:26
2 Answers
Constructors can't be virtual.
Calling a virtual method in the base's constructor is problematic, because the derived object doesn't exist yet.
What you can instead do is provide a factory function that calls populate
after constructing the object.
class Base
{
template <typename Derived, typename... Args>
static Derived make(Args&&... args)
{
Derived result(std::forward<Args>(args)...);
result.populate();
return result;
}
protected:
Base() = default;
virtual void populate() = 0;
};

- 52,200
- 2
- 44
- 75
The key part of your question is this:
However, the constructor must populate the grid to provide a reasonable functionality.
That's the required postcondition of all subclasses. Unfortunately, there's no way of enforcing that short of unit-testing every ctor to confirm that it actually does what you want.
Delegating to any form of late dispatch and requiring the implementation via an abstract member function doesn't actually bypass the problem. Sure, it might make it harder to "forget" about fulfilling that postcondition, but you still need to write unit tests for that, so in practice you gain nothing.
The only way to enforce anything in C++ is to ask for a value. You'd need to hide the default constructors, and expose static factory member functions that would return e.g. pair<ObjectConstructed, GridFootprint>
. Then you could enforce non-emptiness on the GridFootprint
contructor.
This approach would work well, but it would require breaking the hidden dependency between your objects and your grid. It might be a good thing, but it's hard to say without seeing the entire problem.

- 38,596
- 7
- 91
- 135