I'm storing into a container a list of pointers to an heterogeneous set of objects, using a string to identify them. Regarding the safety of this operation, I've already discussed here and I'm fine with that.
The problem is that when the class has multiple inheritance and I try to cast the same pointer to either one or the other super class, it seems that the second cast fails.
Here is an example:
#include <iostream>
#include <map>
using namespace std;
class A {
public:
virtual void hello() = 0;
};
class B {
public:
virtual void goodbye() = 0;
};
class C : public A,
public B
{
public:
void hello() override {
std::cout << "C says: Hello World!" << std::endl;
}
void goodbye() override {
std::cout << "C says: GoodBye World!" << std::endl;
}
};
class D : public A {
public:
void hello() override {
std::cout << "D says: Hello World!" << std::endl;
}
};
class E : public B {
public:
void goodbye() override {
std::cout << "E says: GoodBye World!" << std::endl;
}
};
int main()
{
std::map <std::string, void*> mymap;
C c;
D d;
E e;
mymap["C"] = (void*) &c;
mymap["D"] = (void*) &d;
mymap["E"] = (void*) &e;
static_cast<A*>(mymap["D"])->hello();
static_cast<B*>(mymap["E"])->goodbye();
static_cast<A*>(mymap["C"])->hello();
static_cast<B*>(mymap["C"])->goodbye();
return 0;
}
The expected output would be:
D says: Hello World!
E says: GoodBye World!
C says: Hello World!
C says: GoodBye World!
but what I get instead is:
D says: Hello World!
E says: GoodBye World!
C says: Hello World!
C says: Hello World!
I don't even know how is that possible since I'm not even calling hello.
EDIT After understanding what has been discussed in the duplicate of and this page, I've ended up with this solution:
int main()
{
std::map <std::string, void*> mymap;
C c;
D d;
E e;
mymap["C"] = static_cast<A*>(&c);
mymap["D"] = static_cast<A*>(&d);
mymap["E"] = static_cast<B*>(&e);
static_cast<A*>(mymap["D"])->hello();
static_cast<B*>(mymap["E"])->goodbye();
static_cast<A*>(mymap["C"])->hello();
dynamic_cast<B*>(static_cast<A*>(mymap["C"]))->goodbye();
return 0;
}
An alternative solution that I've found is also making the second class inherit from the previous:
...
class B : public A{
public:
virtual void goodbye() = 0;
};
class C : public B
{
public:
void hello() override {
std::cout << "C says: Hello World!" << std::endl;
}
void goodbye() override {
std::cout << "C says: GoodBye World!" << std::endl;
}
};
...
int main()
{
std::map <std::string, void*> mymap;
C c;
D d;
mymap["C"] = static_cast<A*>(&c);
mymap["D"] = static_cast<A*>(&d);
static_cast<A*>(mymap["D"])->hello();
static_cast<A*>(mymap["C"])->hello();
dynamic_cast<B*>(static_cast<A*>(mymap["C"]))->goodbye();
return 0;
}