Ambiguity of 'this' and 'member function' [modified]
-
This code below occurs no error but the result seems a bit weird.
class KBase
{
public:
void BaseFun()
{
printf( "KBase::BaseFun() this=%p\n", this );
}
};class KMiddle : public KBase
{
};class KMiddle2 : public KBase
{
};class KDerived : public KMiddle, public KMiddle2
{
};int main()
{
KDerived d;d.KBase::BaseFun(); // 0012FF63 d.KMiddle::BaseFun(); // 0012FF63 d.KMiddle2::BaseFun(); // 0012FF64 ?? return 0;
}//main()
BaseFun simply shows this pointer and the result goes.. --------------------------- KBase::BaseFun() this=0012FF63 KBase::BaseFun() this=0012FF63 KBase::BaseFun() this=0012FF64 --------------------------- So my question is why KBase::BaseFun() and KMiddle::BaseFun() show the same address and the only KMiddle2::BaseFun() does the different address? I was looking for the answer by reading Stephen Prata's book and Effective C++ but I couldn't. Thanks in advance.
modified on Wednesday, August 24, 2011 9:51 PM
-
This code below occurs no error but the result seems a bit weird.
class KBase
{
public:
void BaseFun()
{
printf( "KBase::BaseFun() this=%p\n", this );
}
};class KMiddle : public KBase
{
};class KMiddle2 : public KBase
{
};class KDerived : public KMiddle, public KMiddle2
{
};int main()
{
KDerived d;d.KBase::BaseFun(); // 0012FF63 d.KMiddle::BaseFun(); // 0012FF63 d.KMiddle2::BaseFun(); // 0012FF64 ?? return 0;
}//main()
BaseFun simply shows this pointer and the result goes.. --------------------------- KBase::BaseFun() this=0012FF63 KBase::BaseFun() this=0012FF63 KBase::BaseFun() this=0012FF64 --------------------------- So my question is why KBase::BaseFun() and KMiddle::BaseFun() show the same address and the only KMiddle2::BaseFun() does the different address? I was looking for the answer by reading Stephen Prata's book and Effective C++ but I couldn't. Thanks in advance.
modified on Wednesday, August 24, 2011 9:51 PM
Which complier do you use? in some complier that follow the standard c++ strictly, like g++, your code will not compiled and got Error Message: `D' is an ambiguous base of `B' To make the multiple inheritance follows the standard c++ well, you should using virtual inheritance in this case.
class KMiddle : virtual public KBase
class KMiddle2 : virtual public KBaseclass KDerived : public KMiddle, public KMiddle2
-
Which complier do you use? in some complier that follow the standard c++ strictly, like g++, your code will not compiled and got Error Message: `D' is an ambiguous base of `B' To make the multiple inheritance follows the standard c++ well, you should using virtual inheritance in this case.
class KMiddle : virtual public KBase
class KMiddle2 : virtual public KBaseclass KDerived : public KMiddle, public KMiddle2
Hi,
xrg_soft@163.com wrote:
Which complier do you use?
I use Visual Studio 2008.
xrg_soft@163.com wrote:
To make the multiple inheritance follows the standard c++ well, you should using virtual inheritance
I know that the multiple inheritance needs virtual inheritance. However, when I don't on purpose, the result seems not understandable. Could you explain to me why those 'this' addresses look unrestrained?
-
This code below occurs no error but the result seems a bit weird.
class KBase
{
public:
void BaseFun()
{
printf( "KBase::BaseFun() this=%p\n", this );
}
};class KMiddle : public KBase
{
};class KMiddle2 : public KBase
{
};class KDerived : public KMiddle, public KMiddle2
{
};int main()
{
KDerived d;d.KBase::BaseFun(); // 0012FF63 d.KMiddle::BaseFun(); // 0012FF63 d.KMiddle2::BaseFun(); // 0012FF64 ?? return 0;
}//main()
BaseFun simply shows this pointer and the result goes.. --------------------------- KBase::BaseFun() this=0012FF63 KBase::BaseFun() this=0012FF63 KBase::BaseFun() this=0012FF64 --------------------------- So my question is why KBase::BaseFun() and KMiddle::BaseFun() show the same address and the only KMiddle2::BaseFun() does the different address? I was looking for the answer by reading Stephen Prata's book and Effective C++ but I couldn't. Thanks in advance.
modified on Wednesday, August 24, 2011 9:51 PM
From "Diamond problem" at Wikipedia[^]:
C++ by default follows each inheritance path separately, so a D object would actually contain two separate A objects, and uses of A's members have to be properly qualified. If the inheritance from A to B and the inheritance from A to C are both marked "virtual" (for example, "class B : virtual public A"), C++ takes special care to only create one A object, and uses of A's members work correctly. If virtual inheritance and nonvirtual inheritance are mixed, there is a single virtual A and a nonvirtual A for each nonvirtual inheritance path to A. Please note that nonvirtual derivation of A in this case will be useless as direct access to any part of class A from class D will practically always end up with compile error.
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler. -- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong. -- Iain Clarke
[My articles] -
Hi,
xrg_soft@163.com wrote:
Which complier do you use?
I use Visual Studio 2008.
xrg_soft@163.com wrote:
To make the multiple inheritance follows the standard c++ well, you should using virtual inheritance
I know that the multiple inheritance needs virtual inheritance. However, when I don't on purpose, the result seems not understandable. Could you explain to me why those 'this' addresses look unrestrained?
In your case(no virtual inheritance used), the The inside of the KDrived object, there is a KMiddle object followed by a KMiddle2 object. d.KBase::BaseFun(); d.KMiddle::BaseFun(); actually calls to the function of the KMiddle object. and d.KMiddle2::BaseFun(); calls to the function of the KMiddle2 object. As your Kxxx object contains nothing, so sizeof(Kxxx) == 1 That's why the result printed. And if you adding somemember variable into the class, then the result should be: KBase::BaseFun() this= KBase::BaseFun() this= KBase::BaseFun() this=<base> + sizeof(KMiddle)
-
In your case(no virtual inheritance used), the The inside of the KDrived object, there is a KMiddle object followed by a KMiddle2 object. d.KBase::BaseFun(); d.KMiddle::BaseFun(); actually calls to the function of the KMiddle object. and d.KMiddle2::BaseFun(); calls to the function of the KMiddle2 object. As your Kxxx object contains nothing, so sizeof(Kxxx) == 1 That's why the result printed. And if you adding somemember variable into the class, then the result should be: KBase::BaseFun() this= KBase::BaseFun() this= KBase::BaseFun() this=<base> + sizeof(KMiddle)
-
From "Diamond problem" at Wikipedia[^]:
C++ by default follows each inheritance path separately, so a D object would actually contain two separate A objects, and uses of A's members have to be properly qualified. If the inheritance from A to B and the inheritance from A to C are both marked "virtual" (for example, "class B : virtual public A"), C++ takes special care to only create one A object, and uses of A's members work correctly. If virtual inheritance and nonvirtual inheritance are mixed, there is a single virtual A and a nonvirtual A for each nonvirtual inheritance path to A. Please note that nonvirtual derivation of A in this case will be useless as direct access to any part of class A from class D will practically always end up with compile error.
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler. -- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong. -- Iain Clarke
[My articles]