maverick786us
June 4th, 2005, 02:20 AM
What is this diamond problem in C++ in multiple inheritance? how does it arise and what is the solution of it?
|
Click to See Complete Forum and Search --> : Diamond problem in C++ maverick786us June 4th, 2005, 02:20 AM What is this diamond problem in C++ in multiple inheritance? how does it arise and what is the solution of it? Vedam Shashank June 4th, 2005, 02:23 AM What is this diamond problem in C++? how does it arise and what is the solution of it? :confused: Smasher/Devourer June 4th, 2005, 02:55 AM Presumably you're referring to the case of having four classes arranged in a multiple inheritance hierarchy like so: http://www.ironblayde.com/temp/diamondproblem.gif The problem here is that if you declare an object of type D, since it inherits from both classes B and C, which in turn both inherit from class A, an object of type D will actually contain two subobjects of type A -- one inherited from B and one from C. So if class A has a member variable called m_Value, and you try something like this: D obj_d; obj_d.m_Value = 0; you'll get an error, because this is ambiguous. Does the reference to m_Value refer to the copy that obj_d has inherited through class B, or the copy it's inherited through class C? For the solution to this problem, read up on virtual inheritance (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/_pluslang_virtual_base_classes.asp). SuperKoko June 4th, 2005, 03:57 AM The Diamond problem arises when a class inherit indirectly two or more times from the same base class. For example a A inherit from T, B inherit from T, and C inherit from A and B (multiple inheritance). If the inheritance is not virtual, then the data space for T is allocated two times for C (all fields are defined twice, and are distinct). First problem : if c is an instance of C, what field c.PublicFieldOfT accesses? In fact the compiler will generate an error: ambiguous base class. The correct method to access the field is: c.A::PublicFieldOfT, or c.B::PublicFieldOfT (explicit class specifiers). There is also an other solution, that allow A and B to share the same instance of T, with the same physical fields in memory: the virtual inheritance: class T { public: int x; }; class A:virtual public T { }; class B:virtual public T { }; class C:public A,public B { }; int main() { C c; std::cout<<&c.x<<&c.A::x<<&c.B::x; // displays three times the same memory address (with non-virtual inheritance : &c.x is illegal (ambiguous), and &c.A::x!=&c.B::x) } With non-virtual inheritance there is another problem: Consider now that T contains a virtual function named Display for example: A and B (non-virtually derived from T) redefine this virtual function: class T { public: virtual void Display() {cout<<"_T_Hello_";} // i write inline functions to type less code, but that is generally stupid, since a virtual function is never inlined when polymorphism is used. }; class A:public T { public: virtual void Display() {cout<<"_A_Hello_";} }; class B:public T { public: virtual void Display() {cout<<"_B_Hello_";} }; class C:public A,public B { }; int main() { C c; c.Display(); // generate a compiler error : ambiguous override of a virtual base member. c.A::Display(); // displays _A_Hello_, and compiles correctly c.B::Display(); // displays _B_Hello_, and compiles correctly return 0; } Note that the fact that T::Display is not pure, has absolutely no effect. Note also that this problem is solved if B::Display if not defined, in that case there is no ambiguity, and A::Display is called. But, probably the better method to solve the ambiguity is to redefine the virtual function in C, and it works! class C:public A,B { virtual void Display() {cout<<"_C_Hello";} }; But, there is of course a conceptual problem: the is-A general rule of inheritance is partially broken: Because C is-A A, and C is-A B, and C is-two-differents T, that behaves a little differently (there is the T of A, and the T of B). Note that when the Display virtual function is redefined in C, C is used in both virtual table of the two base classes of C: And for example converting C to A, and passing a pointer to A to a function that uses the Display virtual function, will display "_C_Hello". That is certainly what you wanted! SuperKoko June 4th, 2005, 03:59 AM I am sorry, but the previous post was to big to be posted in only once, so this post is the continuation of the previous: If you want A and B share the same T, you must use virtual inheritance: class T { public: virtual void Display() {cout<<"_T_Hello_";} }; class A:virtual public T { public: virtual void Display() {cout<<"_A_Hello_";} }; class B:virtual public T { public: virtual void Display() {cout<<"_B_Hello_";} }; class C:public A,public B { }; // there is a compiler error at the declaration-level of C, because there is an ambiguous virtual member. C has only one instance of T inside it, and only one virtual pointer table, so what pointer can you put in it? &A::Display or &B::Display! So, it is absolutely necessary (but that was not necessary with non-virtual inheritance), to redefine the virtual function in the C declaration. The correct code is: class C:public A,public B { virtual void Display() {cout<<"_C_Hello_";} // the ambiguity is solved. }; There is also a case, where this redefinition is not necessary : if A or B does not redefine the Display method, then there is no ambiguity and B::Display or A::Display is used. And if A::Display is not defined, neither B::Display, then T::Display is used, and if T::Display is pure, than of course T, A, and B are abstract, and C must define Display. With virtual inheritance the is-A rule works perfectly: C is-a A, and C is-a B, and A is-a T, and B is-a T, and C is-the-same-T that A and B are. C++ solves the Diamond problem, with the rule : when there is no ambiguity it works, and if there is an ambiguity the programmer must redefine the virtual functions (if there is virtual inheritance, because ambiguity is inherent, at the class-definition-and-declaration-level), or must use explicit specifiers to indicate to what T it refers (in the case of non-virtual inheritance only, because there are two "instances" of T, so the ambiguity is only a problem at the code-that-access-level, and using A:: or B:: solve the problem). codeguru.com
Copyright Internet.com Inc., All Rights Reserved. |