Reputation: 173
This isn't a question about how to do something, I know well about virtual inheritance, and I know of a few ways to circumvent this problem - but none that I am happy about.
Here is some code that doesn't compile:
struct BottomClass
{
BottomClass(int& ref) : ref(ref) {}
int& ref;
};
struct MiddleClassA : virtual public BottomClass
{
MiddleClassA() /*: BottomClass()*/ {}
virtual ~MiddleClassA() = 0;
};
MiddleClassA::~MiddleClassA(){}
struct MiddleClassB : virtual public BottomClass
{
MiddleClassB() /*: BottomClass()*/ {}
virtual ~MiddleClassB() = 0;
};
MiddleClassB::~MiddleClassB(){}
struct TopClass final : public MiddleClassA, public MiddleClassB
{
TopClass(int& ref) : BottomClass(ref) {}
};
void main()
{
int someInt;
TopClass variable(someInt);
}
What bothers me is why this doesn't compile. I know that there is no default constructor for BottomClass and hence MiddleClassX is ill-formed. But MiddleClassX are abstract classes! Even if I specified a constructor there it wouldn't be used under any circumstances... so why should I specify that?
I couldn't even give a sensible constructor there because MiddleClassX doesn't have any reasonable value to give to the BottomClass.
My question is: is there an elegant solution to this problem?
I have a few solutions myself, but I don't like any of them especially:
1) I could create a BottomClass default constructor that uses some garbage value to construct its ref. And then assert() in that constructor so I know it is never called... Of course this leads to me having to do run-time checking of everything that should be a compile-time error, and it also practically demands the existence of a garbage integer to get the reference of.
2) I could pass the reference to every abstract middle class and use that... But this leads to serious repetition of information, and when these chains get long (as they do) it is very tedious to maintain that. There is also the performance hit of having to pass an extra variable to every class.
(I apologize if my question is hard to understand - if anyone can better describe my dilemma that would be awesome, I'm challenged to put this into words)
Upvotes: 1
Views: 247
Reputation: 106216
Why not declare a default constructor...
BottomClass(); // deliberately undefined; use Bottom(int&)
...and leave it undefined - at worst you get a link-time error if an actual attempt to use it is made.
See on ideone.com
Upvotes: 1
Reputation: 169201
Even if I specified a constructor there it wouldn't be used under any circumstances
Wrong. Constructors on abstract classes are used by derived classes. Abstract classes can still require initialization after all, the only thing special about abstract classes is that you can't directly construct them; only derived classes are allowed to construct them, and only as part of their own construction.
An abstract class with no constructors can't be derived, just like any other class with no constructors can't be derived.
Your second solution is the right one. If the constructors up the chain are inlined then there is no performance hit at all.
(By the way, this has nothing at all to do with virtual inheritance. You will run into the same problem with non-virtual inheritance.)
Upvotes: 1