Hi,
I have a problem with virtual inheritance between 2 compilers. The 2 compilers are Visual Studio 2010 and Borland C++ 2009 (Embarcadero).
I declare the 3 interfaces below :
class IA
{
public:
virtual void __stdcall methodInA() = 0;
};
class IB : public virtual IA
{
public:
virtual void __stdcall methodInB() = 0;
};
class IC : public virtual IA
{
public:
virtual void __stdcall methodInC() = 0;
};
I implements an object D in a dll compiled with Visual Studio :
class D : public virtual IB, public virtual IC
{
public:
D()
{
OutputDebugStringA("D created : ");
char tmp[32];
sprintf(tmp,"this=0x%08X\r\n",this);
OutputDebugStringA(tmp);
}
~D()
{
OutputDebugStringA("D deleted : ");
char tmp[32];
sprintf(tmp,"this=0x%08X\r\n",this);
OutputDebugStringA(tmp);
}
virtual void __stdcall methodInA()
{
char tmp[64];
sprintf(tmp,"D::methodInA() : this=0x%08X\r\n",this);
OutputDebugStringA(tmp);
}
virtual void __stdcall methodInB()
{
char tmp[64];
sprintf(tmp,"D::methodInB() : this=0x%08X\r\n",this);
OutputDebugStringA(tmp);
}
virtual void __stdcall methodInC()
{
char tmp[64];
sprintf(tmp,"D::methodInC() : this=0x%08X\r\n",this);
OutputDebugStringA(tmp);
}
};
in the dll, one method is exported to get a pointer on one of the interface IA, IB, or IC from an instance of D.
Everything works perfectly if the dll is used in a program compiled with Visual Studio.
But when I load the dll in a Borland C++ program:
if I get a pointer on the IA interface, I can call methodInA:
OK:)
if I get a pointer on the IB interface,
call to methodInB fails!:( (in fact, call to methodInA fails too)
Using disassembly on both side (a borland client program and a VS client program), I found differences to access the virtual tables of the interface IB.
My question is: Does any one know if there is an option in one of the 2 compilers to make them compatible? And
Removing virtual inheritance is not an answer :).
Remark: __stdcall is a way I found to allow method call between Borland Prog and Visual dll (same way to put args on the stack)
Visual Studio uses "thiscall" by default for the class methods, it is equivalent to __stdcall except for the this pointer put in register ecx and not in the stack.
After removing virtual inheritance:
#define iid(intf,iid) const int iid_##intf = iid
#define iidof(intf) (iid_##intf)
iid(IA,0);
class IA
{
public:
virtual void* __stdcall Query(int iid) = 0;
virtual int __stdcall AddRef() = 0;
virtual int __stdcall Release() = 0;
virtual void __stdcall methodInA() = 0;
};
iid(IB,1);
class IB : public IA
{
public:
virtual void __stdcall methodInB() = 0;
};
iid(IC,2);
class IC : public IA
{
public:
virtual void __stdcall methodInC() = 0;
};
If I create a class D like this one, it will work.
class D : public IA, public IB, public IC
{
protected:
int refCount;
virtual ~D()
{
}
public:
D() : refCount(0)
{
}
virtual void* __stdcall Query(int iid)
{
char tmp[128];
void *ptr=NULL;
switch(iid)
{
case iidof(IA):
ptr=(IA*)this;
break;
case iidof(IB):
ptr = (IB*)this;
break;
case iidof(IC):
ptr = (IC*)this;
break;
}
if(ptr!=NULL) AddRef();
return ptr;
}
virtual int __stdcall AddRef()
{
return ++refCount;
}
virtual int __stdcall Release()
{
int lRefCount=--refCount;
if(lRefCount==0)
delete this;
return lRefCount;
}
virtual void __stdcall methodInA()
{
}
virtual void __stdcall methodInB()
{
}
virtual void __stdcall methodInC()
{
}
};
But if I want to create an A class like this one, to get all common task of the IA interface in one class:
class A : public IA
{
protected:
int m_refCount;
virtual ~A()
{
}
public:
A() : m_refCount(0)
{
}
virtual int __stdcall AddRef()
{
++m_refCount;
return m_refCount;
}
virtual int __stdcall Release()
{
int refCount = --m_refCount;
if(refCount==0)
delete this;
return refCount;
}
};
If I inherit the D class from A (instead of IA), I need to reimplement the AddRef and Release because the compiler will not associate the IB::AddRef needed in D with the AddRef from A
Error message from Visual Studio Compiler:
error C2259: 'D' : can not instantiate an abstract class
because of the following members :
'int IA::AddRef(void)' : is abstract
virtualinheritance.h(12) : see declaration of 'IA::AddRef'
'int IA::Release(void)' : is abstract
virtualinheritance.h(13) : see declaration of 'IA::Release'
'int IA::AddRef(void)' : is abstract
virtualinheritance.h(12) : see declaration of 'IA::AddRef'
'int IA::Release(void)' : is abstract
virtualinheritance.h(13) : see declaration of 'IA::Release'
the actual error message may be different, it is translated from french
The following D class is OK:
class D : public A, public IB, public IC
{
protected:
virtual ~D()
{
}
public:
D()
{
}
virtual void* __stdcall Query(int iid)
{
void *ptr=NULL;
switch(iid)
{
case iidof(IA):
ptr=(IA*)(A*)this; break;
case iidof(IB):
ptr = (IB*)this;
break;
case iidof(IC):
ptr = (IC*)this;
break;
}
if(ptr!=NULL) A::AddRef();
return ptr;
}
virtual int __stdcall AddRef()
{
int result = A::AddRef();
return result;
}
virtual int __stdcall Release()
{
int result = A::Release();
return result;
}
virtual void __stdcall methodInA()
{
}
virtual void __stdcall methodInB()
{
}
virtual void __stdcall methodInC()
{
}
};
But there is less interest in creating the A class if you need to add all the methods from the IA in the final class.