简体   繁体   English

如何从包含基类指针的容器中调用派生类函数(基于其类型)?

[英]How to call derived class function (based on its type) from a container which contain pointer of base class?

I inherit from Base class to create two different Derived class ( Derived1 and Derived2), then I place them into a vector. 我从基类继承来创建两个不同的派生类(派生1和派生2),然后将它们放入向量中。 Lets say I want to call the function of Derived class based on the type of class. 可以说我想根据类的类型调用Derived类的函数。

pseudocode: 伪代码:

if holder[1] stored Derived1 then I want to call GetZ() 
else if holder[1] stored Derived2 then I want to GetFlag(). 

An attempt: 尝试:

#include <iostream>
#include <memory>
#include <vector>

class Base {
 public:
  Base(int x, int y) : x_(x), y_(y) {}

  int GetX() { return x_; }
  int GetY() { return y_; }

 private:
  int x_;
  int y_;
};

class Derived1 : public Base {
 public:
  Derived1(int x, int y, int z) : Base(x, y), z_(z) {}

  int GetZ() { return z_; }

 private:
  int z_;
};

class Derived2 : public Base {
 public:
  Derived2(int x, int y, bool flag) : Base(x, y), flag_(flag) {}

  bool GetFlag() { return flag_; }

 private:
  bool flag_;
};

std::vector<std::shared_ptr<Base>> holder;
void print();
int main() {
  holder.push_back(std::make_shared<Derived1>(3, 4, 5));
  holder.push_back(std::make_shared<Derived2>(6, 7, true));

  print();
}

void print(){

  for(auto& it : holder){
    // call this if "it" is Derived2
    // else call it->GetX()
    // currently this gives compilation error 
    // because of object slicing
    std::cout << it->GetFlag() << std::endl;
  }

}
for(auto& it : holder){
  if (auto* D1 = dynamic_cast<Derived1*>(it->get())) {
    std::cout << D1->GetZ();
  } else if (auto* D2 = dynamic_cast<Derived2*>(it->get())) {
    std::cout << D2->GetFlag();
  }
  std::cout << std::endl;
}

dynamic cast is usually code smell, evidence that your interface Base is missing functionality. 动态转换通常是代码味道,证明您的接口Base缺少功能。 Once you dynamic cast, your interface goes from what Base states to the layout and contents of your entire type heirarchy. 动态转换后,您的界面将从Base状态变为整个类型继承结构的布局和内容。

Instead, add: 相反,添加:

virtual boost::optional<int> GetZ() { return {}; }
virtual boost::optional<bool> GetFlag() { return {}; }

to Base , and override in derived. Base ,并在派生中重写。

for(auto& it : holder){
  if (auto Z = it->GetZ()) {
    std::cout << *Z;
  } else if (auto flag = it->GetFlag())
    std::cout << *flag;
  }
  std::cout << std::endl;
}

now we no longer care which specific derived type we used to implement Z or Flag . 现在我们不再关心我们用来实现ZFlag特定派生类型。

From this SO answer there is a link to a reference std::optional implementation that uses the boost software license and is one header file. 这个SO答案中有一个指向参考std :: Optional实现链接,该实现使用boost软件许可证,并且是一个头文件。

check the good ol' dynamic_cast trick – if it's castable, it's of the right type. 检查良好的dynamic_cast技巧-如果它是可转换的,则类型正确。

Anyway, I'd recommend not using this design pattern (check types at runtime and decide based on that), but put the logic into the derived classes; 无论如何,我建议不要使用这种设计模式(在运行时检查类型并根据其进行决定),而是将逻辑放入派生类中。 have a common method that either does the one or the other thing: 有一个可以做一件事或另一件事的通用方法:

class Base {
 public:
  Base(int x, int y) : x_(x), y_(y) {}

  int GetX() { return x_; }
  int GetY() { return y_; }

  virtual int do_the_right_thing();

 private:
  int x_;
  int y_;
};

class Derived1 : public Base {
 public:
  Derived1(int x, int y, int z) : Base(x, y), z_(z) {}

  int GetZ() { return z_; }

  virtual int do_the_right_thing() { return GetZ() };

 private:
  int z_;
};

class Derived2 : public Base {
 public:
  Derived2(int x, int y, bool flag) : Base(x, y), flag_(flag) {}

  bool GetFlag() { return flag_; }

  virtual int do_the_right_thing() { return GetFlag() };

 private:
  bool flag_;
};


void print(){

  for(auto& it : holder){
    // call this if "it" is Derived2
    // else call it->GetX()
    // currently this gives compilation error 
    // because of object slicing
    std::cout << it->do_the_right_thing() << std::endl;
  }

}

The STL-style way of dealing with this would be templates and type traits – but I personally consider that to be a nuisance. STL风格的处理方式是模板和类型特征-但我个人认为这很麻烦。

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

相关问题 如何从指向基类类型的指针调用派生类函数(C ++) - How to call derived class function from pointer to base class type (C++) 在基类中,如何定义一个包含函数obj的容器,它可以是派生类的任何函数? - in base class, how to define a container to contain function obj which can be any func of derived class? 如何通过基类指针调用派生类的虚函数 - How to call virtual function of derived class through base class pointer 派生类指针如何调用基类函数 - how a derived class pointer can call the base class function 如何从基类指针调用派生类方法? - How to call derived class method from base class pointer? 派生类的指针是否可以类型转换为其基类的指针? - Can a pointer of a derived class be type cast to the pointer of its base class? 通过指向派生类的函数调用基本虚方法 - Call base virtual method by pointer to function from derived class 来自派生类的调用函数,该派生类存储在具有基类类型的Map中 - Call function from Derived class stored in a Map with Base class type 如何从 function 调用派生类的方法,期望基本 class 指针? - How can I call a derived class's method from a function expecting the a base class pointer? 如何通过派生的指针在基类中调用模板成员函数 - How to call template member function in the base class by the derived pointer
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM