Could I do this?
class A {
public:
virtual void aFoo() = 0;
};
class B : virtual public A {
public:
virtual void aFoo() { ... }
};
class D : public A {};
class C : public B, virtual public D {};
The issue is with the implementation of aFoo() in B and the lack of it in C. When it comes to compiling I see this error:
error: no unique final overrider for ‘virtual void A::aFoo()’ in ‘C’
Shouldn't it be possible to override a pure virtual method of a virtual base class in B?
Just edited the example to match the actual use case. Now looking at it in this simplified way I am not quite sure if this is even possible, let alone good design.
You need virtual inheritance in this way:
struct A {
virtual int f() = 0;
};
struct B : virtual A {
int f() { return 1; }
};
struct C : virtual A {};
struct D : B, C {};
int main() {
D d;
return d.f();
}
In the dupe I commented you can see this relation
A
/ \
B C
\ /
D
for virtual inheritance and
A A
| |
B C
\ /
D
without virtual inheritance.
In the second case D contains two function definitions. One is implemented and one isn't.
Related
Suppose a pure abstract base class might be inherited by multiple paths in a dreaded diamond of death. Is there any good reason to use virtual inheritance, or doesn't it matter?
There is a good reason to use virtual inheritance, because the compiler will enforce it. Consider this scenario:
struct A {
virtual ~A() = default;
virtual void f() = 0;
};
struct B : A {};
struct C : A {};
struct D : B, C {
void f() override {}
};
Without virtual inheritance, the following code won't compile
D d;
A &a = d; // error: 'A' is an ambiguous base of 'D'
When you change B and C such that
struct B : virtual A {};
struct C : virtual A {};
everything will build just fine.
I have produced a minimal example to replicate the problem I am seeing with a more complex class hierarchy structure:
#include <string>
#include <iostream>
class A
{
protected:
virtual
~A() = 0;
};
inline
A::~A() {}
class B : public A
{
public:
virtual
~B()
{
}
std::string B_str;
};
class BB : public A
{
public:
virtual
~BB()
{
}
std::string BB_str;
};
class C : public A
{
protected:
virtual
~C()
{
}
virtual
void Print() const = 0;
};
class D : public B, public BB, public C
{
public:
virtual
~D()
{
}
};
class E : public C
{
public:
void Print() const
{
std::cout << "E" << std::endl;
}
};
class F : public E, public D
{
public:
void Print_Different() const
{
std::cout << "Different to E" << std::endl;
}
};
int main()
{
F f_inst;
return 0;
}
Compiling with g++ --std=c++11 main.cpp produces the error:
error: cannot declare variable ‘f_inst’ to be of abstract type ‘F’
F f_inst;
note: because the following virtual functions are pure within ‘F’:
class F : public E, public D
^
note: virtual void C::Print() const
void Print() const = 0;
^
So the compiler thinks that Print() is pure virtual.
But, I have specified what Print() should be in class E.
So, I've misunderstood some of the rules of inheritance.
What is my misunderstanding, and how can I correct this problem?
Note: It will compile if I remove the inheritance : public D from class F.
Currently your F is derived from C in two different ways. This means that an F object has two separate C bases, and so there are two instances of C::Print().
You only override the one coming via E currently.
To solve this you must take one of the following options:
Also override the one coming via D, either by implementing D::Print() or F::Print()
Make Print non-pure
Use virtual inheritance so that there is only a single C base.
For the latter option, the syntax adjustments would be:
class E : virtual public C
and
class D : public B, public BB, virtual public C
This means that D and E will both have the same C instance as their parent, and so the override E::Print() overrides the function for all classes 'downstream' of that C.
For more information , look up "diamond inheritance problem". See also Multiple inheritance FAQ
I have produced a minimal example to replicate the problem I am seeing with a more complex class hierarchy structure:
#include <string>
#include <iostream>
class A
{
protected:
virtual
~A() = 0;
};
inline
A::~A() {}
class B : public A
{
public:
virtual
~B()
{
}
std::string B_str;
};
class BB : public A
{
public:
virtual
~BB()
{
}
std::string BB_str;
};
class C : public A
{
protected:
virtual
~C()
{
}
virtual
void Print() const = 0;
};
class D : public B, public BB, public C
{
public:
virtual
~D()
{
}
};
class E : public C
{
public:
void Print() const
{
std::cout << "E" << std::endl;
}
};
class F : public E, public D
{
public:
void Print_Different() const
{
std::cout << "Different to E" << std::endl;
}
};
int main()
{
F f_inst;
return 0;
}
Compiling with g++ --std=c++11 main.cpp produces the error:
error: cannot declare variable ‘f_inst’ to be of abstract type ‘F’
F f_inst;
note: because the following virtual functions are pure within ‘F’:
class F : public E, public D
^
note: virtual void C::Print() const
void Print() const = 0;
^
So the compiler thinks that Print() is pure virtual.
But, I have specified what Print() should be in class E.
So, I've misunderstood some of the rules of inheritance.
What is my misunderstanding, and how can I correct this problem?
Note: It will compile if I remove the inheritance : public D from class F.
Currently your F is derived from C in two different ways. This means that an F object has two separate C bases, and so there are two instances of C::Print().
You only override the one coming via E currently.
To solve this you must take one of the following options:
Also override the one coming via D, either by implementing D::Print() or F::Print()
Make Print non-pure
Use virtual inheritance so that there is only a single C base.
For the latter option, the syntax adjustments would be:
class E : virtual public C
and
class D : public B, public BB, virtual public C
This means that D and E will both have the same C instance as their parent, and so the override E::Print() overrides the function for all classes 'downstream' of that C.
For more information , look up "diamond inheritance problem". See also Multiple inheritance FAQ
Given the following code (without virtual inheritance) :
class A
{
public:
virtual void f() = 0;
};
class B : public A
{
public:
virtual void f() {}
};
class C : public A
{
public:
virtual void f() {}
};
class D : public B, public C
{
/* some code */
};
int main()
{
D d;
return 0;
}
the code compile.
On the other hand , here :
class A
{
public:
virtual void f() = 0;
};
class B : virtual public A
{
virtual void f() {}
};
class C : virtual public A
{
virtual void f() {}
};
class D : public B, public C
{
/* some code */
};
int main()
{
D d;
return 0;
}
The compiler presents a compilation error:
no unique final overrider for 'virtual void A::f()' in 'D' .
Why is it different in the second code ?
Your first scenario hierarchy corresponds to:
F() F()
A A
| |
F() B C F()
\ /
D
Where D is not abstract, because there are two A subobjects in an object of type D: One that is made concrete by B through the lattice of B, and another that is made concrete through the lattice of C.
Unless you try to invoke the function F() on object of D there will not be any ambiguity.
Your second scenario hierarchy corresponds to:
F()
A
/ \
F() B C F()
\ /
D
In this scenario, the object D has a single Base class A sub object, and it must override and provide implementation of the pure virtual function in that subobject.
Herb Sutter's articles in Guru Of The Week(GOTW) are a nice read for Multiple Inheritance:
Multiple Inheritance Part I
Multiple Inheritance Part II
Multiple Inheritance Part III
With the virtual inheritance a D object has a single base-class A sub-object. This single sub-object can’t have two different implementations of a virtual function. In contrast, without virtual inheritance a D object has two distinct base-class A sub-objects, each with its own implementation of the function (which is OK until you try to call it on a D object, at which point you need to indicate which one you want).
Cheers & hth.
Assume the following:
class A{ virtual void f() = 0; };
class B{ virtual void f() = 0; };
Can I do the following somehow?
class C : public A, public B
{
virtual void A::f(){ printf("f() from A"); }
virtual void B::f(){ printf("f() from B"); }
};
So now I can do???
A* pa = new C();
pa->f(); // prints f() from A;
B* pb = (B*)pa;
pb->f(); // prints f() from B;
Thanks!!!
First solution
This question remind the 'facade' design pattern.
This should be re-write as this :
class AC : public A
{ public: virtual void f(){ cout << "f() from A" << endl;}; };
class BC : public B ...
class C : public AC, public BC {};
where C is the 'facade'.
So in the correct calling syntax should be something like that :
C* c = new C();
c->AC::f();
c->BC::f();
If you don't have any share constraint between AC & BC this should do the job as it is'nt offuscated.
Second solution
Another solution, thank to Casey (see first comment), is to use a forward declaration of the class C in a template to allow calls to methods define latter.
template <typename C>
class AC : public A {
public:
void f() { static_cast<C&>(*this).f_from_A(); }
};
template <typename C>
class BC : public B { ... };
so the implementation part can be done in the same class.
class C : public AC<C>, public BC<C> {
public:
void f_from_A() { cout << "f_from_A" << endl; };
void f_from_B() ...
};
The calling part is cleaner because it doesn't show any implementation details and it is closest to the question :
C* c = new C();
((A*) c) -> f();
((B*) c) -> f();
There is no more 'default' f() on C and it is possible to break the expected behavior of inheritance, and it is harder to read.
For reference, the following links seem related:
Overloading virtual functions of the same name from different base classes. Is it possible?
C++ virtual override functions with same name
Derived class defines function via base class
The OP in the second link asked if he could do something like you asked:
class Impl : public A , public B
{
public:
void A::Function () { cout << "A::Function" << endl; }
void B::Function () { cout << "B::Function" << endl; }
};
Johannes answer is:
You cannot use qualified names there. I you write void Function() {
... } you are overriding both functions. Herb Sutter shows how it can
be solved.
Another option is to rename those functions, because apparently they
do something different (otherwise i don't see the problem of
overriding both with identical behavior).
So one possible solution (by James Kanze from the first link) looks like this:
class RemapA : public A
{
virtual void fnInA() = 0;
public:
virtual void fn()
{
fnInA();
}
};
class RemapB : public B
{
virtual int fnInB() = 0;
public:
virtual int fn()
{
return fnInB();
}
};
class C : public RemapA, public RemapB
{
virtual void fnInA() { /* ... */ }
virtual void fnInB() { /* ... */ }
// ...
};
Herb Sutter's link essentially says the same thing.
For overriding both function you need intermediate classes. A using declaration in C selects the function of A:
#include <iostream>
struct A{ virtual void f() = 0; };
struct B{ virtual void f() = 0; };
struct IntermediateA : public A {
virtual void f() override { std::cout << "A\n"; }
};
struct IntermediateB : public B {
virtual void f() override { std::cout << "B\n"; }
};
struct C : public IntermediateA, public IntermediateB
{
using IntermediateA::f;
};
int main() {
C c;
B* b = &c;
c.f();
b->f();
return 0;
}
Yes. Each base class has its own virtual table.
So by casting, the compiler will check the virtual table of the type you're casting to, and get the pointer to the matching function there.
class A {public: virtual void f() = 0; };
class B {public: virtual void f() = 0; };
class C : public A, public B
{
public:
virtual void A::f(){ printf("f() from A"); }
virtual void B::f(){ printf("f() from B"); }
};
GCC doesn't support this. Only Visual Studio does.
But you will have to always use a cast or a scoped function call.
This will return an ambiguous call error:
C* c = new C();
c->f(); //ambiguous call compilation error
This will work:
((B*)c)->f();
The compiler shows the structure like this: (Visual studio flag: /d1reportSingleClassLayoutC)
class C size(8):
+---
| +--- (base class A)
0 | | {vfptr}
| +---
| +--- (base class B)
4 | | {vfptr}
| +---
+---
C::$vftable#A#:
| &C_meta
| 0
0 | &C::f
C::$vftable#B#:
| -4
0 | &CCCC::f
C::f this adjustor: 4
C::f this adjustor: 0
Basically you can see the 2 separate pointers for the matching virtual tables.
So you could do:
C* c= new C();
B* b = (B*)c;
b->f(); // calls C::B::f()
A* a = (A*)c;
a->f(); // calls C::A::f()
or even:
a = (A*)(C*)b;
a->f(); // calls C::A::f()
Note that you need to case b back to the derived class to access the virual table of the A type base class.