multiple inheritance oddnes

D

dice

This is a condensed version of a problem I came across today, can
anyone explain what is going on?

If the code below is run nothing will be output (in the original
problem it was causing exeptions).

if all the virtual destructors are commented out it outputs 'e'
or if
"class InterfaceImpl : public Base, public Interface"
is changed to
"class InterfaceImpl : public Interface, public Base"
it also outputs 'e'

in the default case (ie that below) *p refers to a "Base" then
p->recvSignal() causes the problem. Why is it not referring to an
"Interface". And to me more strangely why does it then refer to an
"Interface" if the virtual destructors are removed?

Thanks in advance for any responses - it will probably be monday before
I get to look at them.

Also at the moment the problem has been worked around simply by
altering the order of the inherited classes as noted above. Is this
safe?

#include <iostream>
using namespace std;

class Interface
{
public:
virtual void recvSignal(char ch) = 0;
virtual ~Interface(){};
};

class Controller
{
public:
void doit()
{
p->recvSignal('e');
};
void addDevice(void* ptr)
{
p = (Interface*)ptr;
};
virtual ~Controller(){};

private:
Interface* p;
};

class Base
{
public:
void nv(){};
virtual ~Base(){};
};

class InterfaceImpl : public Base, public Interface
{
public:
void recvSignal(char ch)
{
cout<<ch<<endl;
};
virtual ~InterfaceImpl(){};
};

class Controlled : public InterfaceImpl
{
public:
void nvgb(){};
virtual ~Controlled(){};
};

int main()
{
Controller ctrl;
Controlled device;

ctrl.addDevice(&device);
ctrl.doit();

return 0;
}
 
V

Victor Bazarov

dice said:
This is a condensed version of a problem I came across today, can
anyone explain what is going on?

If the code below is run nothing will be output (in the original
problem it was causing exeptions).

if all the virtual destructors are commented out it outputs 'e'
or if
"class InterfaceImpl : public Base, public Interface"
is changed to
"class InterfaceImpl : public Interface, public Base"
it also outputs 'e'

[..]
Also at the moment the problem has been worked around simply by
altering the order of the inherited classes as noted above. Is this
safe?

Absolutely not.
#include <iostream>
using namespace std;

class Interface
{
public:
virtual void recvSignal(char ch) = 0;
virtual ~Interface(){};
};

class Controller
{
public:
void doit()
{
p->recvSignal('e');
};
void addDevice(void* ptr)
{
p = (Interface*)ptr;

This cast here is BOGUS, and the source of your error. Rework it
_without_ a C-style cast, and you will find THE RIGHT WAY(tm).
};
virtual ~Controller(){};

private:
Interface* p;
};

class Base
{
public:
void nv(){};
virtual ~Base(){};
};

class InterfaceImpl : public Base, public Interface
{
public:
void recvSignal(char ch)
{
cout<<ch<<endl;
};
virtual ~InterfaceImpl(){};
};

class Controlled : public InterfaceImpl
{
public:
void nvgb(){};
virtual ~Controlled(){};
};

int main()
{
Controller ctrl;
Controlled device;

ctrl.addDevice(&device);
ctrl.doit();

return 0;
}

V
 
A

Andrey Tarasevich

dice said:
This is a condensed version of a problem I came across today, can
anyone explain what is going on?
...
class Controller
{
public:
void doit()
{
p->recvSignal('e');
};
void addDevice(void* ptr)
{
p = (Interface*)ptr;
};
virtual ~Controller(){};

private:
Interface* p;
};

class Base
{
public:
void nv(){};
virtual ~Base(){};
};

class InterfaceImpl : public Base, public Interface
{
public:
void recvSignal(char ch)
{
cout<<ch<<endl;
};
virtual ~InterfaceImpl(){};
};

class Controlled : public InterfaceImpl
{
public:
void nvgb(){};
virtual ~Controlled(){};
};

int main()
{
Controller ctrl;
Controlled device;

ctrl.addDevice(&device);
ctrl.doit();

return 0;
}

The above 'addDevice' call will convert a pointer of type 'Controlled*' to a
pointer of type 'Interface*' through an intermediate type 'void*':

Controlled* -> void* -> Interface*

This will not produce a usable 'Interface*' value in general case. The direct
conversion

Controlled* -> Interface*

would work fine, of course, but that 'void*' in the middle destroys everything,
because it hides the relationship between the source and target pointers from
the compiler.

If you really need that intermediate 'void*' (why?), then changing the order of
multiple bases is not a good workaround (this won't solve anything in the long
run). One way to deal with it is to perform the 'Controlled* -> Interface*'
conversion explicitly before you convert to 'void*'

// in main()
ctrl.addDevice((Interface*) &device);

This will work regardless of the order of base classes. But, once again, the
better way to solve it is to get rid of that 'void*' entirely. Why do you need
it anyway?
 
D

dice

Andrey said:
The above 'addDevice' call will convert a pointer of type 'Controlled*' to a
pointer of type 'Interface*' through an intermediate type 'void*':

Controlled* -> void* -> Interface*

This will not produce a usable 'Interface*' value in general case. The direct
conversion

Controlled* -> Interface*

would work fine, of course, but that 'void*' in the middle destroys everything,
because it hides the relationship between the source and target pointers from
the compiler.

If you really need that intermediate 'void*' (why?), then changing the order of
multiple bases is not a good workaround (this won't solve anything in the long
run). One way to deal with it is to perform the 'Controlled* -> Interface*'
conversion explicitly before you convert to 'void*'

// in main()
ctrl.addDevice((Interface*) &device);

This will work regardless of the order of base classes. But, once again, the
better way to solve it is to get rid of that 'void*' entirely. Why do you need
it anyway?

in the original real problem addDevice(void*) is actually called from
within a device object as ctrl.addDevice(this). The idea was that the
function should be Controller::addDevice(Interface *) but when this
would not compile stating something along the lines that the cast
"exists but is not accessible" addDevice was changed to use void*
triggering the current badness. I cannot give the exact error as I
dont have access to the code at the moment but it was as if the base
class implementation was somehow hidden - though they are all public in
the declarations. I will give a more exact desctiption of the error
when trying to use addDevice(Interface *) on monday.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,430
Messages
2,571,676
Members
48,796
Latest member
Greg L.

Latest Threads

Top