Understanding how to solve ambiguous member requests in c++ - c++

How do I use a function in class A from class D without inheriting class A and (although I understand it's bad practise, I am not permitted to alter the inheritance at all) and not remove the inheritance from C and B in D? I cannot seem to find a way around the request for member is ambiguous error. I was (wrongly) of the understanding that no matter how far removed the
class A
{
public:
void DoEverything(int){ }
};
class B : public A
{
public:
...
};
class C : public A
{
public:
...
};
class D : public C : public B
{
public:
...
};
int main()
{
D dMan;
int i = 2;
dMan.DoEverything(i);
}
My example is loosely based on the "Ambiguous base classes (C++ only)" example found here: http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/topic/com.ibm.xlcpp8a.doc/language/ref/cplr138.htm#cplr138 but that hasn't helped me understand the problem.

First of all, to make it work just do the following changes
class B : virtual public A
...
class C : virtual public A
This problem in multiple inheritance is called the diamond problem. Check out this link to know more
http://www.cprogramming.com/tutorial/virtual_inheritance.html

Related

Upcasting to a C++ class that is a base class in more than one way (without having to use virtual inheritance)

class A { };
class B : public A {};
class C : public A, public B {};
int main()
{
C c;
A *pA = static_cast<A *>(&c);
}
In the above code, class C is derived from class A in two different paths:
1. Directly from A
2. Indirectly through B i.e. A<-B<-C
So, when I cast an object of class C into a pointer to class A, g++ on Linux reports the following error:
error: A is an ambiguous base of C
I have also tried the same code by removing the static cast as follows:
A *pA = &c;
But, I still get exactly the same error.
Is there any solution for this? BTW, the same works fine without error on Windows using Visual C++ compiler.
I know that virtual inheritance solves this but I need a solution to make this work on g++ on Linux without having to use virtual inheritance. Rather than having to use virtual inheritance, is there any way I can instead specify one of the two path and get rid of the ambiguity. Many thanks!
If you can modify C, one possible approach would be to "inject" a dummy base class between it and A:
class A { };
class B : public A {};
class AlmostA : public A {};
class C : public AlmostA, public B {};
int main()
{
C c;
A *pA = static_cast<A*>(static_cast<AlmostA*>(&c));
}
[Live example]
You can even embed the dual static casts into a function in C.
Long story short, inherit from A virtually to avoid having two distinct As being a part of C:
class A { };
class B : virtual public A {};
class C : virtual public A, public B {};
Now your code will compile and run correctly.
Unlike "regular" base classes, virtual base classes are inherited only once, regardless of the number of paths that have them. Read this Q&A for a detailed explanation of how they work.

base class ambiguous when converting derived class pointer to base class

I'm using C++. When I try to convert a derived class' pointer to base class', compiler complains "base class is ambiguous".
I did some research, and found this question How can I avoid the Diamond of Death when using multiple inheritance?. And some other similar issue.
There is a solution, is to use virtual inheritance. But I'm not able to change class definitions, because they are compiled libraries.
Is that possible to do the converting, without changing base class definitions?
A minimal sample would be:
class A {};
class B : public A {};
class C : public A {};
class D : public B, public C {};
What I want to do is:
D *d = new D;
A *a = (D *)d; // ambiguous
Is that possible to do the converting, without changing base class definitions?
Yes it is. You have to choose which direct base class to go through.
class A {};
class B : public A {};
class C : public A {};
class D : public B, public C {};
void foo(A&) {}
int main() {
D d;
foo(static_cast<B&>(d));
foo(static_cast<C&>(d));
return 0;
}
I found a way to do this converting, a little tricky though.
Following code would do the job:
A *a = (B *)d;

C++ Multilevel Inheritance, Polymorphism

Suppose i have three classes A, B and C. class B inherits from class A and the inheritance is private whereas class C inherits from B and the inheritance is public. Now class A has a protected function which class C wants to access. So, what must be done in class B to make that protected function available to class C.
Here is the link to the code : http://pastebin.com/9E2sLZzj
The "using" keyword makes a member of an inherited class visible, and resolvable, in the scope of its subclass. So, to make the privately-inherited member available to B's subclasses:
class A {
protected:
void foo() {}
};
class B : private A {
protected:
using A::foo;
};
class C : public B {
void bar()
{
foo();
}
};
Okay i got the solution
This code fragment worked after inserting it into Class B.
int get(){
return A::get();
}
Not sure what it does though

Share instance of base class for indirect base classes possible?

I must admit I'm having trouble formulating this question, but I'll try my best to be precise. I have tried to search for an answer to my question, but I suspect I have been unable to find what I'm looking for, as I'm not exactly sure what to call this.
I have a base class A, and several child classes inheriting from this base class. I then make another class X that inherits from some of the mentioned child classes. The problem I'm now facing is that each of the classes X inherits, have their own instance of class A. The code below should give a better understanding of what I mean.
class A;
class B : public A;
class C : public A;
class X : public B, public C;
Is there a way to make class B and C share the same instance of class A, when they are both acting as indirect base classes for the same class?
To give an example of why I want this, lets look at this code.
class A
{
int _x;
};
class B : public A
{
void outputX(){std::cout << A::_x << std::endl;
};
class C : public A
{
void setX(int x){A::_x=x;}
};
class X : public B, public C
{
C::setX(5);
// this will output an un-initialized _x,
// as B and C have their own version of A
B::outputX()
};
Now I realize this seems rather unnecessary in this example here, but in my real situation I like to think it would be a good solution if B and C shared instance of A in class X.
Is this at all possible?
You can solve this by using virtual inheritance:
class B : virtual public A;
class C : virtual public A;
class X : virtual public B, virtual public C;
See more on the diamond problem.

Refer base class members from derived class

class A {
public:
void fa() {
}
};
class B : public A{
public:
void fb() {
}
};
class C : public A, public B {
public:
void fc() {
//call A::fa(), not B::A::fa();
}
};
How to call A::fa() from C::fc() function.
GCC warns withdirect base A inaccessible in C due to ambiguity, does this mean there is no direct way to refer base class members?
One option would be to create a stub class that you can use for casting to the right base class subobject:
struct A {
void fa() { }
};
struct B : A {
void fb() { }
};
// Use a stub class that we can cast through:
struct A_ : A { };
struct C : A_, B {
void fc() {
implicit_cast<A_&>(*this).fa();
}
};
Where implicit_cast is defined as:
template <typename T> struct identity { typedef T type; }
template <typename T>
T implicit_cast(typename identity<T>::type& x) { return x; }
I just found the following info from ISO C++ 2003 standard (10.1.3)
A class shall not be specified as a direct base class of a derived class more than once. [Note: a class can be
an indirect base class more than once and can be a direct and an indirect base class. There are limited
things that can be done with such a class. The non-static data members and member functions of the direct
base class cannot be referred to in the scope of the derived class. However, the static members, enumerations
and types can be unambiguously referred to.
It means there is no direct way :(
I just compiled you code on codepad.org , putting A::fa() is enough to call fa() from your C::fc() function.
void fc() {
A::fa();
}
The below is the link to codepad with your code.
http://codepad.org/NMFTFRnt
I don't think you can do what you want. There is an ambiguity here: when you say A::fa(), it still doesn't tell the compiler which A object to use. There isn't any way to access class A. That's what the warning is telling you.
This seems like an awfully strange construct, though. Public inheritance should be used for is-a relationships. You are saying that C is-a A twice over? It doesn't make sense. And that suggests that this is either an artificial example that would never come up in practice, or you should reconsider this design.
You can use virtual inheritance to overcome such problem:
class B : virtual public A {
Now, you can use A::fa() simply in the child class C.
void fc()
{
fa();
}
However, I generally don't see any practical need to inherit class A again into class C, when B is already publically inheriting A. So, In your case, you can make it simple:
class C : public B {
Edit:
If you want 2 instances for A. then the direct instance which you are intending can be made as an object of C:
class C : public B {
A obj;
Because, having a directly inherited A will not be usable in anyway. You cannot declare any pointer or reference to it inside the scope of C.