当前位置: 首页 > 知识库问答 >
问题:

向多个继承类的超级类强制执行void*不会调用正确的方法[重复]

万高轩
2023-03-14

我在一个容器中存储了一个指向一组异构对象的指针列表,使用一个字符串来标识它们。关于这次行动的安全性,我已经在这里讨论过了,我没意见。

问题是,当类有多重继承,并且我试图将同一个指针转换到一个或另一个超类时,第二次转换似乎会失败。

下面是一个示例:

#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: GoodBye World!

但我得到的却是:

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

我发现的另一种解决方案也是使第二个类继承前一个类:

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

共有1个答案

段干博涉
2023-03-14

您的代码具有未定义的行为。

给定一个转换成< code>B*的< code>void*,计算机没有办法知道< code>B子对象在哪里(在实际上是< code>C的指向对象中)。你只是假装整个东西(或者,至少,它的前缀)是一个< code>B,如果它是一个简单的单一继承,这将是正确的…但是你的不是;第一垒是一个< code>A,不是一个< code>B。

不要像这样擦除带有 void* 的类型。

 类似资料:
  • 问题内容: 假设我有多个继承方案: 有编写的两个典型方法的: (老式) (较新的样式) 但是,无论哪种情况,如果父类(和)没有遵循相同的约定,则代码将无法正常工作(某些代码可能会丢失,或被多次调用)。 那么又是什么正确的方法呢?说“保持一致,遵循一个或另一个”很容易,但是如果或来自第三方图书馆,那又如何呢?有没有一种方法可以确保所有父类构造函数都被调用(以正确的顺序,并且只能调用一次)? 编辑:看

  • 问题内容: 假设我有以下两个课程 如果我启动一个beta类型的新对象,如何执行在alpha类而不是beta中找到的逻辑?我可以使用<-我想知道是否可行。 Eclipse IDE中的自动键入功能使我可以选择从class 或class中进行选择。 问题答案: 你可以做: 注意,这是对父级的引用,但是super()是它的构造函数。

  • 我想在更深层次的继承中为一个类实现构建器模式,其中一些字段是强制性的(message,case),而一些字段是可选的(myOptField1,MyOptField2…)通过使用Lombok@Builder并假设父类不能更改。因此,我实现了自己的builder(),如下所示: 那么这个类的使用方式可以是: 在IntelliJ的想法中,一切似乎都很好,但我得到了编译错误: 因此编译器只能看到由Lomb

  • 假设我有一个继承链,其中每个类都通过添加一个新字段来扩展其超类,我希望该链的每个类都覆盖方法,如下所示: 如果我使用抽象基类,那么当继承链的一个类通过实现抽象方法变得具体时,从那时起的所有子类也通过继承已经实现的方法变得具体。 Java中有没有一种方法可以强制每个类重写(重新实现)抽象方法,即使它已经在继承链中实现得更高?

  • 您可以看到,我正在将“that”作为参数传递给PrintInfo。如果没有“that”参数,“info”将打印为“undefined”。像下面的例子一样,当从“子类”的对象调用此函数时,“this.info”是未定义的。 如何在javascript中重写和调用超类的方法,使函数能够访问类的实例变量?