如何从包含基类指针的容器中调用派生类函数(基于其类型)?
How to call derived class function (based on its type) from a container which contain pointer of base class?
我从基类继承来创建两个不同的派生类(Derived1和Derived2(,然后将它们放入向量中。假设我想根据类的类型调用派生类的函数。
伪代码:
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
,并在派生中覆盖。
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
的特定派生类型。
从这个 SO 答案中,有一个指向参考 std::可选实现的链接,该实现使用 boost 软件许可证并且是一个头文件。
检查好的dynamic_cast
技巧 - 如果它是可铸造的,它是正确的类型。
无论如何,我建议不要使用这种设计模式(在运行时检查类型并据此做出决定(,而是将逻辑放入派生类中;有一个通用方法可以做一件事或另一件事:
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;
}
}
STL风格的处理方式是模板和类型特征 - 但我个人认为这很麻烦。
相关文章:
- 如何通过派生类函数更改基类中的向量
- 虚拟基类函数中派生类的大小
- 调用不在基类中的派生类函数而不进行动态强制转换,以最大程度地提高性能
- 在将派生类指针类型转换为派生类指针后,从基类指针调用派生类函数
- 如何使派生类函数在调用时始终调用相同的基类函数?
- 有没有办法在没有虚拟的情况下使用基类指针调用派生类函数
- 如何从派生类函数中调用虚拟函数
- C++虚拟函数:基类函数是调用的,而不是派生的
- 即使基类和派生类只使用基元数据类型,我是否需要定义虚拟析构函数
- C++通过 const 引用传递时不调用派生类函数
- 有没有办法调用基类函数,该函数在使用私有继承的派生类中被覆盖?
- 是否可以在引用另一个派生类的派生类中声明复制构造函数?
- 如何从包含基类指针的容器中调用派生类函数(基于其类型)?
- 从多重继承中的派生类函数调用适当的父类函数
- 从具有泛型返回类型的 crtp 基类调用派生类中的函数
- 使用单一实例类作为派生类时,如何访问基类中的函数
- 无法访问派生类函数内的基类的受保护数据成员
- 调用不属于基类的派生类函数的最佳方法是什么?
- 将 final 关键字添加到没有基类(未派生)的类中的虚函数是否有意义
- 从派生类对象调用基类函数.派生类构造函数中设置的基类数据成员