In C++ multiple inheritance with virtual base
i understand why could this code be ambiguous , but why it still complains when i specifically call a derived class method ?
class A {
public:
virtual void f() { cout << 1 ;}
};
class B :virtual public A {
public:
virtual void f() { cout << 2; }
};
class C :virtual public A {
public:
virtual void f() { cout << 3; }
};
class D : public B, public C {};
void main(){
D* d = new D();
d->B::f();
getch();
}
i would expect that it will run the B:f() method but i get :
"ambiguous inheritance of 'void A::f(void)'
The problem is that your function is virtual which means it overrides address in vtable. You can't override one address with two functions.
Without virtual qualifier there would be just ambiguity during the call which can be avoided just like you did specifying base class B::f()
The problem is that your class D has two final overriders of function f. See http://en.cppreference.com/w/cpp/language/virtual about final overrider.
Related
Can I have a virtual function in the base class and some of my derived classes do have that function and some don't have.
class A{
virtual void Dosomething();
};
class B : public A{
void Dosomething();
};
class C : public A{
//Does not have Dosomething() function.
};
From one of my c++ textbook:
Once a function is declared virtual, it remains virtual all the way down the inheritance, even if the function is not explicitly declared virtual when the derived class overrides it.
When the derived class chooses not to override it, it simply inherits its base class's virtual function.
Therefore to your question the answer is No. Class c will use Class A's virtual function.
Derived classes do not have to implement all the virtual functions, unless it is a pure virtual function. Even in this case, it will cause an error only when you try to instantiate the derived class( without implementing the pure virtual function ).
#include <iostream>
class A{
public :
virtual void foo() = 0;
};
class B: public A{
public :
void foo(){ std::cout << "foo" << std::endl;}
};
class C: public A{
void bar();
};
int main() {
//C temp; The compiler will complain only if this is initialized without
// implementing foo in the derived class C
return 0;
}
I think the closest you might get, is to change the access modifier in the derived class, as depicted below.
But, I would consider it bad practice, as it violates Liskov's substitution principle.
If you have a situation like this, you might need to reconsider your class design.
#include <iostream>
class A {
public:
virtual void doSomething() { std::cout << "A" << std::endl; }
};
class B : public A {
public:
void doSomething() override { std::cout << "B" << std::endl; };
};
class C : public A {
private:
void doSomething() override { std::cout << "C" << std::endl; };
};
int main(int argc, char **args) {
A a;
a.doSomething();
B b;
b.doSomething();
C c;
//c.doSomething(); // Not part of the public interface. Violates Liskov's substitution principle.
A* c2 = &c;
c2->doSomething(); // Still possible, even though it is private! But, C::doSomething() is called!
return 0;
}
I have a homework for my programming course that asks me to designs an abstract from whom derive two classes, and from those two derived classes derives another class.
This brings the Deadly Diamond of Death problem. Which can be solved by virtual inheritance, though I need instance the objects of my first two classes to a pointer of my abstract class. And this can't be done with any kind of virtual inheritance. So, if there is a way to specify the base class from which the multiple inheritance class will derive, it would be astronomically useful.
Example:
#include <iostream>
using namespace std;
class Base {
public:
virtual void foo(){};
virtual void bar(){};
};
class Der1 : public Base {
public:
virtual void foo();
};
void Der1::foo()
{
cout << "Der1::foo()" << endl;
}
class Der2 : public Base {
public:
virtual void bar();
};
void Der2::bar()
{
cout << "Der2::bar()" << endl;
}
class Join : virtual Der1, virtual Der2 {
private:
int atribb;
};
int main()
{
Base* obj = new Join();
((Der1 *)(obj))->foo();
}
Compiler error:
nueve.cpp: In function ‘int main()’:
nueve.cpp:43:30: error: ‘Base’ is an ambiguous base of ‘Join’
Base* obj = new Join();
Use virtual inheritance.
class Der1 : public virtual Base {
public:
virtual void foo();
};
class Der2 : public virtual Base {
public:
virtual void bar();
};
If virtual is declared while deriving from base class, as shown in below example, the most derived class object contains only one base class sub object, which helps in resolving the ambiguity in your case.
After doing some code changes, your final executable code:
Code changes in below sample:
Added vitual key word, while deriving the child classes.
Removed "virtual" keyword while deriving most derived class.
Modified main to invoke the member function properly.
#include <iostream>
using namespace std;
class Base {
public:
virtual void foo(){};
virtual void bar(){};
};
class Der1 : public virtual Base {
public:
virtual void foo();
};
void Der1::foo()
{
cout << "Der1::foo()" << endl;
}
class Der2 : public virtual Base {
public:
virtual void bar();
};
void Der2::bar()
{
cout << "Der2::bar()" << endl;
}
class Join : public Der1, public Der2 {
private:
int atribb;
};
int main()
{
Base* obj = new Join();
obj->foo();
}
It's not clear what you're asking for, although you seem to be saying that virtual inheritance from Base is not suitable. So, assuming that's correct, you can replace Base* obj = new Join(); with Base* obj = (Der1*)new Join(); and you'll get a pointer to the Base object that's the base of Der1. Similarly, you can replace it with Base* obj = (Der2*)new Join(); and you'll get a pointer to the Base object thats the base of Der2.
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
I have stumbled on a problem while trying to re-use code from different classes. I post it here in hope that some of you might be able to help me.
I have a set of classes (B,C) deriving from the same class (A) which forces the implementation of some methods (foo, run). Class B implements these method, and both B and C provide other methods:
#include<iostream>
template<class I, class O>
class A {
public:
A() {}
virtual ~A() {}
virtual void foo() const = 0; // force implementation of this function
virtual void run() const = 0; // force implementation of this function
};
template<class I, class O>
class B : public A<I,O> {
public:
B() {}
virtual ~B() {}
virtual void foo() const { // implementation for the Base class
std::cout << "B's implementation of foo" << std::endl;
}
virtual void run() const { // implementation for the Base class
std::cout << "B's implementation of run" << std::endl;
}
virtual void foobar() const { // some other function provided by this class
std::cout << "B's implementation of foobar" << std::endl;
}
};
template<class I, class O, class M>
class C : public A<I,O> {
public:
C() {}
virtual ~C() {}
virtual void bar(M m) const { // some other function provided by this class
std::cout << "C's implementation of bar with: " << m << std::endl;
}
};
Now, what I am trying to do is inherit from both B and C so that I can have the extra methods (foobar, bar), but also not have to implement the method from class A (foo) because it is already defined in B:
template<class I, class O>
class D : public B<I,O>, public C<I,O,int> {
public:
D() {}
void run() const {
this->bar(123);
this->foo();
this->foobar();
}
};
But for some reason the compiler gives me this error:
test.cpp: In function ‘int main(int, char**)’:
test.cpp:68:35: error: cannot allocate an object of abstract type ‘D<float, double>’
A<float, double> *d = new D<float, double>(); // what I need to do
test.cpp:48:11: note: because the following virtual functions are pure within ‘D<float, double>’:
class D : public B<I,O>, public C<I,O,int> {
^
test.cpp:9:22: note: void A<I, O>::foo() const [with I = float; O = double]
virtual void foo() const = 0; // force implementation of this function
This is the code I use to run it:
int main(int argc, char **argv)
{
A<float, double> *b = new B<float, double>();
b->foo(); // prints "B's implementation of foo"
b->run(); // prints "B's implementation of run"
//A<float, double> *c = new C<float, double, int>(); // obviously fails because C does not implement any of A's functions
//A<float, double> *d = new D<float, double>; // line 68: what I need to do
//d->run(); // ***throws the abstract class error
return 0;
}
I want to use the 'run' function of an object of class D from a pointer to a A. As all the functions are virtual I expect to execute implementation of each function defined in the lowest inheritance point, meaning that 'B::run' will be discarded. As 'D::run' uses functions from both B and C I need to inherit from both classes.
I hope I have described it enough and not confused anybody.
Thanks for the help!
If you change B and C to virtually inherit from the A template class, they will share a single base instance when combined by D and this error will go away:
template<class I, class O>
class B : virtual public A<I,O> {
// ...
template<class I, class O, class M>
class C : virtual public A<I,O> {
However, this pattern (known as the diamond inheritance (anti-)pattern) can be very difficult to reason about and I would strongly suggest avoiding it if possible. You are likely to run into even more obscure problems later.
Here is a sample of this technique working, but showing some results that may not be expected at first glance:
class A {
public:
virtual void foo() = 0;
};
class B : virtual public A {
public:
virtual void foo() override;
};
void B::foo()
{
std::cout << "B::foo()" << std::endl;
}
class C : virtual public A { };
class D : public B, public C { };
int main() {
D d;
C & c = d;
c.foo();
return 0;
}
Note that even though you are calling C::foo(), which is pure virtual, since there is only one A instance the inherited pure virtual function resolves to B::foo() though the shared A vtable. This is a somewhat surprising side-effect -- that you can wind up invoking methods implemented on a cousin type.
The answer by #cdhowie gives you a solution.
To understand the problem the compiler is complaining about, take a set of simpler classes:
struct A
{
virtual void foo() = 0;
};
struct B : A
{
virtual void foo() {}
}
struct C : A
{
void bar() {}
}
struct D : B, C
{
};
The class hierarchy of D is:
A A
| |
B C
\ /
D
With this inheritance structure, D has two virtual tables, one corresponding to the B inheritance hierarchy and one corresponding to C inheritance hierarchy. The difference being that in the B hierarchy, there is an implementation of A::foo() while there isn't one in the C hierarchy.
Let's say you were allowed to construct an object of type D.
D d;
C* cp = &d;
Now cp points to the C hierarchy of D, and uses a virtual table in which foo is not implemented. That will be a run time error that the compiler is helping you avoid at compile time.
I know this is a late answer but since you are deriving from a pure virtual function for class C, you have to implement it, then in those functions you call the base class:
virtual void foo() const { // for class C
B::foo();
}