我继承自基类以创建两个不同的派生类(Derived1 和 Derived2),然后将它们放入一个 vector 中。假设我想根据类的类型调用派生类的函数。
伪代码:
if holder[1] stored Derived1 then I want to call GetZ()
else if holder[1] stored Derived2 then I want to GetFlag().
一次尝试:
#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;
}
动态转换通常是代码异味,表明您的界面 Base
缺少功能。动态转换后,您的界面将从 Base
状态变为整个类型层次结构的布局和内容。
相反,添加:
virtual boost::optional<int> GetZ() { return {}; }
virtual boost::optional<bool> GetFlag() { return {}; }
到 Base
,并在 derived 中覆盖。
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;
}
现在我们不再关心我们使用哪个特定的派生类型来实现 Z
或 Flag
。
来自 this SO answer有一个link to a reference std::optional implementation使用boost软件许可证,是一个头文件。
关于c++ - 如何从包含基类指针的容器中调用派生类函数(基于其类型)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45446072/