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.
Related
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.
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;
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
I have class C and it is inheriting from Class A and Class B.
Is it possible for class A to access Class B function( eg fun1() ) using this inheritance. A and B are both independent class and fun1() is only in class B.
Not strictly through inheritance. Although A and B are parents of C, A and B have no relationship and no way to access eachother.
It is possible through inheritance and polimorphism, then class A have a virtual method that C implements calling the function in B, like this:
class A {
public:
b get_b() { return do_get_b(); }
private:
virtual do_get_b() = 0;
};
class B {
public:
b some_b;
};
class C : public A, public B {
private:
virtual do_get_b() {return some_b;}
}
You could check with dynamic_cast to see if your object of A is really a object of C, and thereby of B
void A::foo()
{
B* pB = dynamic_cast<B*>(this);
if (pB) pB->bar();
}
But if A and B are really independent of one another it is probably better to find a different solution.
Sometimes, it is possible. An example how to achieve this.
That example applies to a diamond hierarchy, which is a bit more complicated than yours. In your terms, ClassA and ClassB should be derived from class Base, ClassC is derived from ClassA and ClassB.
Short story:
is it possible to do
class A{};
class B:public virtual A{};
class C:public virtual A,private B{};
i.e. "showing" that C is an A and not a B, but making it actually a B
without adding the virtual (and the corresponding vptrs)?
Long story:
A has several methods.
B adds some more.
Sometimes I want to forbid the use of one of them. C has this purpose.
The program has many B, few Cs. I do not want then to make B a subclass of C.
Yes, this will do exactly what you intend it to do.
But consider another option: inheriting publicly and hiding the unwanted methods:
class A
{
public:
int a() {return 0xaa;}
};
class B: public A
{
public:
int b() {return 0xbb;}
};
class C: public B
{
private:
using B::b; // makes the method called b private
};
...
B().b(); // OK, using method b in class B
C().b(); // error: b is private in class C
C().B::b(); // OK: calling b in base-class (not sure if you want to prevent this)
This will work with both virtual and non-virtual inheritance.