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;
}