I have this
A
/ \
B C
\ /
D
A has a pure virtual function, prototyped as:
virtual A* clone(void) const = 0;
B and C virtually inherit from A ( class B: public virtual A, class C: public virtual A)
B has the virtual function, prototyped as:
virtual B* clone(void) const {};
C has the virtual function, prototyped as:
virtual C* clone(void) const {};
D inherits from both B & C like that: class D: public B, public C
D has the virtual function, prototyped as:
virtual D* clone(void) const {};
Now, when compiling I get the following 6 lines of errors:
error C2250: 'D' : ambiguous inheritance of 'B *A::clone(void) const'
No freaking idea how to solve this issue.
Thanks in advance.
Use virtual inheritance if you want only one copy of a parent in your hierarchy.
class B : public virtual A
Edit:
There may be a bug in MSVC++ 2010. The Intellisense doesn't detect a problem, but the compiler chokes on it. Strange since VC6 is happy enough with it.
As a workaround, if you declare D as follows, it makes MSVC++ 2010 happy while also working in compilers without this issue:
class D: public virtual A, public B, public C
What you describe in your original post is perfectly legal. A quick sample code that does exactly that compiles without any errors by Comeau Online compiler
class A {
public: virtual A* clone() const = 0;
};
class B: public virtual A {
public: virtual B* clone() const { return 0; }
};
class C: public virtual A {
public: virtual C* clone() const { return 0; }
};
class D: public B, public C
{
public: virtual D* clone() const { return 0; }
};
Either you are not doing what you said you are doing, or your compiler is broken. Post real code you are trying to compile.
P.S. I just tried compiling this in VS 2010 Express and got the same error. As Gunslinger47 also suggests in the comments, this is a bug in VS 2010 compiler.
avoid diamond inheritance? ;->
anyway, here is sample (really sample - don't cast like that)
// ConsoleCppTest.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "iostream"
class A {
public:
virtual void* clone() = 0;
};
class B: public A {
public:
virtual void* clone() = 0;
};
class C: public A {
public:
virtual void* clone() = 0;
};
class D: public B, public C
{
public:
virtual void* B::clone()
{
std::cout << "B";
return (void*)this;
}
virtual void* C::clone()
{
std::cout << "C";
return (void*)this;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
D* d = new D();
void* b = ((B*)d)->clone();
void* c = ((C*)d)->clone();
return 0;
}
Related
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.
I'm working on an assignment involving 4 classes and diamond inheritance. I've based all my answers on an assumption that may or may not be correct.
The diamond hierarchy is like this:
A
/ \
B C
\ /
D
and the code looks like this:
class A
{
private:
string s;
public:
A(string s);
virtual ~A;
virtual void set(string s);
virtual string get();
};
class B : public virtual A
{
public:
void set(string s);
string get();
}
class C : public virtual A
{
public:
void set(string s);
}
class D : public B, public C
{
public:
void set(string s);
}
Suppose I have a pointer that looks like this:C *obj = new D();
If get is called on obj, the pointer will actually end up looping back to D and then invoke B's get method. A C object alone would end up invoking A's get method. Assuming B and A's get methods return different results, which result would be expected?
The code you provided unfortunately won't compile as is.
We can create a similar example and just try it:
#include <cstdio>
struct A
{
virtual char const * get() {return "a";};
virtual ~A() = default;
};
struct B : public virtual A
{
char const * get() override {return "b";};
};
struct C : public virtual A
{
//char const * get() override {return "c";};
};
struct D : public B, public C
{
//char const * get() override {return "d";};
};
int main()
{
A* a = new A();
B* b = new B();
C* c = new C();
C* d = new D();
printf("%s\n", a->get());
printf("%s\n", b->get());
printf("%s\n", c->get());
printf("%s\n", d->get());
delete a;
delete b;
delete c;
delete d;
}
which gives:
a
b
a
b
isocpp calls this delegating to a sister class
As B and C both virtually inherit A, there is only a single instance of A, therefore in the virtual table, when B overrides an implementation of A, only a single member overrides get and this becomes also overridden for D.
Should you also uncomment the the get method in C, then we would get:
virtual.cc:19:8: error: no unique final overrider for 'virtual const char* A::get()' in 'D'
19 | struct D : public B, public C
|
However, further modifying the example and also uncommenting the get in D would make the code compile again. Now returning:
a
b
c
d
It will act like a D object.
Just like with single inheritance, it acts like the class that was created (not what the pointer to it is).
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 some troubles with the application of polymorphism in this example. This question is similar to my last question
C++, virtual inheritance, strange abstract class + clone problem
There are 3 abstract classes:
class A
{
public:
virtual A * copy () const = 0;
virtual ~A() = 0;
};
A::~A(){}
class B
{
public:
virtual B * copy () const = 0;
virtual ~B() = 0;
};
B::~B(){}
class C: virtual public A , public B
{
public:
virtual C * copy () const = 0;
virtual ~C() = 0;
};
C::~C(){}
and two inherited classes using the virtual inheritance
class D: virtual public A
{
public:
virtual D * copy () const {return new D (*this);}
virtual ~D() {}
};
class E: virtual public D , public C
{
public:
virtual E * copy () const {return new E (*this);}
virtual ~E() {}
}; //Error C2250: 'E' : ambiguous inheritance of 'D *A::copy(void) const
The above mentioned error occurs only using MSVS 2010 compiler, g++ compiles this code OK.
Class diagram (simplified)
.......... A .... B.....
........../.\..../......
........./...\../.......
......../.....\/........
.......D...... C........
........\...../.........
.........\.../..........
..........\./...........
...........E............
Last discussion we close with the result: remove the declaration of the copy() method from class C.
class C: virtual public A , public B
{
public:
//virtual C * copy () const = 0; //remove declaration
virtual ~C() = 0;
};
C::~C(){}
My sample code using polymorphism needs to create vector of pointers to C. After removing some element I want to create its copy... I NEED a declaration of copy() in class C, so removal of the declaration is insufficient and it does not solve the problem.
int main(int argc, char* argv[])
{
std::vector <C*> items;
items.push_back(new E());
items.push_back(new E());
items[0]->copy();
return 0;
}
Could you help me, please how to correct the code to be translatable using VS 2010?
This is a known bug in Visual C++:
Visual C++ incorrectly reports ambiguity when covariance is used with virtual inheritance
You either need to eliminate the covariance or the virtual inheritance. Unfortunately, you can't have both.