C++ 将void*强制转换为多继承类的超类不会';不要调用正确的方法

C++ 将void*强制转换为多继承类的超类不会';不要调用正确的方法,c++,casting,multiple-inheritance,void-pointers,C++,Casting,Multiple Inheritance,Void Pointers,我正在将指向一组异构对象的指针列表存储到一个容器中,并使用字符串来标识它们。关于这次手术的安全性,我已经讨论过了,我同意 问题是,当类有多个继承时,我试图将同一指针强制转换为一个或另一个超类,第二个强制转换似乎失败了 以下是一个例子: #include <iostream> #include <map> using namespace std; class A { public: virtual void hello() = 0; }; class B { pub

我正在将指向一组异构对象的指针列表存储到一个容器中,并使用字符串来标识它们。关于这次手术的安全性,我已经讨论过了,我同意

问题是,当类有多个继承时,我试图将同一指针强制转换为一个或另一个超类,第二个强制转换似乎失败了

以下是一个例子:

#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;
}
但我得到的是:

D says: Hello World!
E says: GoodBye World!
C says: Hello World!
C says: Hello World!
我甚至不知道这怎么可能,因为我甚至没有打电话给你好

编辑 在理解了和本页副本中讨论的内容后,我最终得出了以下解决方案:

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;
}
intmain()
{
std::map mymap;
C C;
D;
E;
mymap[“C”]=静态转换(&C);
mymap[“D”]=静态投影(&D);
mymap[“E”]=静态投影(&E);
静态_cast(mymap[“D”])->hello();
静态_cast(mymap[“E”])->再见();
静态_cast(mymap[“C”])->hello();
动态播放(静态播放(mymap[“C”])->再见();
返回0;
}
我发现的另一种解决方案是让第二个类继承前一个类:

...
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;
}
。。。
B类:公共A{
公众:
虚空();
};
丙类:公共乙类
{
公众:
void hello()覆盖{

std::cout您的代码具有未定义的行为

如果将
void*
转换为
B*
,计算机无法知道
B
子对象的位置(在实际为
C
的指向对象中)。您只是假装整个对象(或至少是它的前缀)是一个
B
,如果它是一个简单的单一继承,这将是正确的……但你的不是;第一个基数是
a
,而不是
B


不要像这样用
void*
擦除类型。

-缺少输出说明问题。这里有UB…@LightnessRacesinOrbit,如前一个问题所述,如果字符串正确并且我确切知道我要强制转换的内容,则操作是安全的。这个问题不同,因为现在有两个超类。我不取消rstand为什么如果我将同一个指针投射到一个或另一个超类,我没有得到正确的函数调用。代码当然比这复杂得多,我也没有找到“定义良好的方法”对于我所遇到的一般性问题,不管怎么说,这超出了本文讨论的范围。也许这有助于直觉:如果你有
cc;
,并且你试图打印
(A*)和
(B*)的地址&c
您将得到两个不同的值,对应于两个子对象。编译器使用正确的偏移量调整指针,因为编译器知道我们正在将
c*
转换为
A*
B*
。如果我们通过
void*
我们会阻止编译器执行调整——因此UB将
C*
转换为
void*
,然后需要将其转换回
C*
,然后,如果需要,可以再次转换为
A*
B*
。我要补充这个答案,如果您想要维护类继承结构,您可能想要拥有一个超类,它是它们的父类,因此您可以你应该写
std::map mymap;
。不要把它当作一个解决方案,这是一个可行的想法。是的,这是一个好主意-为win@VictorHMartin我已经希望通过父类实现该解决方案,但不幸的是,原始类是模板化的,并且没有假设所有的模板参数可以有一个共同的祖先。我刚刚发现,我试图做的似乎是类型擦除,所以我需要使用
std::any
。顺便说一句,原始代码是开源的,并且是。
...
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;
}