Re: Weird V-table issue
harsh.murari@gmail.com wrote in news:d1a75289-561f-4e38-8b31-
dec004e36966@a1g2000hsb.googlegroups.com:
Thanks for all the replies. I do understand that the standard way of
doing things is to use virtual inheritance and dynamic casting.
However, I would like to clarify that I am working on an embedded
environment (and due to some other reasons which I do not want to
detail here), and I am restricted to using non-virtual inheritance and
no dynamic casting.
Further clarification on QueryInterface: I would like to define a
generic method which all the other interfaces inherit. All the
implementation objects implement the QueryInterface() method to return
the interfaces they they implement. In such a scenario, the out-
parameter of the QueryInterface has to be a void **. Is there any
better method of accomplishing what I am trying to do.
Thanks in advance,
Harsh
I think the problem is that someone somewhere needs to know the layout
of the virtual tables in the actual class that you are using. That is
what dynamic_cast brings to the table. I suppose you can keep your own
table of pointers to the various interfaces and provide a means to
access it from every interface. Then you could avoid the use of
dynamic_cast. Maybe someone else will have a more clever idea for you
though. The following seems to work:
#include <stdio.h>
#include <string>
#include <map>
class IBase
{ public:
virtual int QueryInterface(std::string const & key , void **ppOut) =
0;
protected:
typedef std::map<std::string, void *> InterfaceMap;
};
class INetworkA
{
public:
virtual int NA() = 0;
virtual int QueryInterface(std::string const & key, void **ppOut) =
0;
};
class INetworkB
{
public:
virtual int NB() = 0;
virtual int QueryInterface(std::string const & key, void **ppOut) =
0;
};
class Network : public IBase, private INetworkA, private INetworkB
{
public:
Network()
{
m_InterfaceMap.insert(std::make_pair("INetworkA", static_cast
<INetworkA *>(this)));
m_InterfaceMap.insert(std::make_pair("INetworkB", static_cast
<INetworkB *>(this)));
}
int F1() { printf("Network::F1()\n"); }
int QueryInterface(std::string const & key, void **ppOut)
{
int found = 0;
InterfaceMap::iterator itFind = m_InterfaceMap.find(key);
if (itFind != m_InterfaceMap.end()) {
*ppOut = itFind->second;
found = 1;
}
return found;
}
private:
int NA() { printf("Network::NA()\n"); return 0;}
int NB() { printf("Network::NB()\n"); return 0;}
InterfaceMap m_InterfaceMap;
};
int main()
{
Network *netObj = new Network();
INetworkA * pINetA;
INetworkB * pINetB;
netObj->QueryInterface ("INetworkA", (void **) &pINetA);
pINetA->NA();
pINetA->QueryInterface ("INetworkB", (void **) &pINetB);
pINetB->NB();
INetworkA * pINetA2;
pINetB->QueryInterface ("INetworkA", (void **) &pINetA2);
pINetA2->NA();
return 0;
}
Obviously, you don't need to use a string as a key, and you can use any
sort of lookup structure you want. This is for illustrative purposes
only. :) In fact, if you have a small fixed number of interfaces, I
would consider an array of void * s as the InterfaceMap and an enum
value as the key. Such as:
enum Interfaces
{
INetworkA,
INetworkB,
InterfaceCount
};
....
class Network : public IBase, private INetworkA, private INetworkB
{
void * m_InterfaceMap[InterfaceCount];
public:
Network() {
m_InterfaceMap[INetworkA] = static_cast<INetworkA *>(this);
m_InterfaceMap[INetworkB] = static_cast<INetworkB *>(this);
// zero out any empty slots
}
int QueryInterface(Interfaces i, void **ppOut) { *ppOut =
m_InterfaceMap[i]; return *ppOut != 0; }
.....
HTH
joe