繁体   English   中英

c++ - 使用派生类作为抽象类容器中函数的参数

[英]c++ - Use derived class as parameter in function from container of abstract class

我有以下类层次结构和一个包装类:

struct Base {
  virtual ~Base() = default;

  virtual void init() = 0;
};

struct DerivedA : Base {
  void init() override {
    // do something specific to DerivedA
  }
};

struct DerivedB : Base {
  void init() override {
    // do something specific to DerivedB
  }
};

struct Wrapper{
  Base* _item;
};

现在,我想要一个Wrapper容器(例如std::vector<Wrapper> )和一个函数f ,它需要两个派生类作为参数,如下所示:

void f(DerivedA* d1, DerivedA* d2) {
  std::cout << "A vs A" << std::endl;
}

void f(DerivedA* d1, DerivedB* d2) {
  std::cout << "A vs B" << std::endl;
}

void f(DerivedB* d1, DerivedB* d2) {
  std::cout << "B vs B" << std::endl;
}

void f(DerivedB* d1, DerivedA* d2) {
  std::cout << "B vs A" << std::endl;
}

int main() {
  std::vector<Wrapper> items;
  items.emplace_back(new DerivedA());
  items.emplace_back(new DerivedB());
  items.emplace_back(new DerivedB());
  items.emplace_back(new DerivedA());

  for (auto i = 0; i < items.size(); i++) {
    for (auto j = i+1; j < items.size(); j++) {
      // do something wizh all item pairs
      f(items[i]._item, items[j]._item);
    }
  }

  return 0;
}

这不会编译,因为编译器确实需要f(Base* b1, Base* b2) ,这当然是有道理的。

到目前为止我尝试过的:

  1. 使用enum class DerivedType { A, B, C }; 解密派生类的类型。 这有效,但似乎很笨拙。
  2. 使用Wrapper的模板化版本并将每个模板类型存储在不同的容器中,例如std::vector<Wrapper<DerivedX>> 再次,这感觉就像我做错了什么。
  3. 使用std::variant<DerivedA, DerivedB> _item代替WrapperBase* _item 但是我无法让std::visit以我要求f的方式返回指向派生类的指针(因为operator()(DerivedX* d)期望对任何X返回相同的返回值)。

有哪些可能的方法来实现这一点? 我正在寻找的解决方案是否存在?

使用基于 RTTI 的解决方案也是一种选择:

void f1(Base* d1, Base* d2) {
    const auto& t1 = typeid(*d1);
    const auto& t2 = typeid(*d2);

    if (t1 == typeid (DerivedA) && t2 == typeid (DerivedA)) {
        std::cout << "A vs A" << std::endl;
    }

    if (t1 == typeid (DerivedA) && t2 == typeid (DerivedB)) {
        std::cout << "A vs B" << std::endl;
    }

    if (t1 == typeid (DerivedB) && t2 == typeid (DerivedA)) {
        std::cout << "B vs A" << std::endl;
    }

    if (t1 == typeid (DerivedB) && t2 == typeid (DerivedB)) {
        std::cout << "B vs B" << std::endl;
    }
}

使用std::variant ,它将是:

struct Wrapper{
  std::variant<DerivedA, DerivedB> _item;
};

int main() {
  std::vector<Wrapper> items {
    { DerivedA()}, 
    { DerivedB()},
    { DerivedB()},
    { DerivedA()}
  };

  for (auto i = 0; i < items.size(); i++) {
    for (auto j = i+1; j < items.size(); j++) {
      // do something with all item pairs here
      std::visit([] (auto& lhs, auto& rhs) { f(&lhs, &rhs); }, items[i]._item, items[j]._item);
    }
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM