dynamic_cast多个派生类
dynamic_cast for multiple derived classes
我有一个基类和n个派生类。我想实例化一个派生类并将其发送到一个函数,该函数接收基类作为参数。在函数内部,我通过使用dynamic_cast找到了它是哪种类型的派生类,但我不想使用几个 if-else 句子。相反,我想知道是否有办法找出它是哪个派生类以便强制转换它。 在这里,我以我的代码为例。
class animal{
public:
virtual ~animal() {}
int eyes;
};
class dog: public animal{
public:
int legs;
int tail;
};
class fish: public animal{
public:
int mostage;
};
void functionTest(animal* a){
if(dynamic_cast<fish*>(a) != NULL){
do_something();
}
else if(dynamic_cast<dog*>(a) != NULL){
do_something();
}
};
我想对此有一个更普遍的方法。类似于dynamic_cast(a(。谢谢!
如果您需要在几分钟内演示某些内容,那么为快速草稿执行此操作会很棒,但通常您会尽量避免以这种方式使用dynamic_cast - 如果在错误的地方使用,可能会导致极高的维护成本。可以使用各种模式,例如简单的方法重载、访问者模式或虚拟的"GetType"函数(如果您喜欢模式,可以使用奇怪的重复模板模式来实现(。
我将列出所有 3 种方法。第一个是迄今为止最直接,最容易使用的。其他 2 个的优点是,它们中的每一个都将要做什么的决定转移到代码的不同部分,这可能是一个巨大的好处(或缺点(。
让我们假设这是您想要做的:
void functionTest(animal* a)
{
if(dynamic_cast<fish*>(a) != NULL)
blub();
else if(dynamic_cast<dog*>(a) != NULL)
bark();
};
简单的虚函数方法:
class animal {
public:
virtual ~animal() {}
virtual void do_something() = 0;
int eyes;
};
class dog : public animal {
public:
virtual void do_something() { bark(); } // use override in C++11
int legs;
int tail;
};
class fish: public animal {
public:
virtual void do_something() { blub(); } // use override in C++11
int mostage;
};
void functionTest(animal* a)
{
if (a) a->do_something();
};
参观方式:
class IVisitor {
public:
~IVisitor(){}
virtual void visit(const fish&){}
virtual void visit(const dog&){}
virtual void visit(const animal&){}
};
class animal {
public:
virtual ~animal() {}
virtual void accept(IVisitor& visitor) = 0;
int eyes;
};
class dog : public animal {
public:
virtual void accept(IVisitor& visitor) { visitor.visit(*this); } // use override in C++11
int legs;
int tail;
};
class fish : public animal {
public:
virtual void accept(IVisitor& visitor) { visitor.visit(*this); } // use override in C++11
int mostage;
};
class MyVisitor : public IVisitor {
public:
virtual void visit(const fish&) { blub(); } // use override in C++11
virtual void visit(const dog&) { bark(); } // use override in C++11
};
void functionTest(animal* a)
{
if (a)
{
MyVisitor v;
a->accept(v);
}
};
GetType方法,带有CRTP香料:
class animal {
public:
virtual ~animal() {}
virtual const type_info& getType() const = 0; // careful. typeinfo is tricky of shared libs or dlls are involved
int eyes;
};
template <class T>
class BaseAnimal : public animal {
// these are C++11 features. Alternatives exist to ensure T derives from BaseAnimal.
static_assert(std::is_base_of<BaseAnimal,T>(,"Class not deriving from BaseAnimal");// C++11
virtual const type_info& getType() const { return typeid(T); }
};
class dog : public BaseAnimal<dog> {
public:
int legs;
int tail;
};
class fish : public BaseAnimal<fish> {
public:
int mostage;
};
void functionTest(animal* a)
{
if (!a)
return;
if (a->getType() == typeid(fish))
blub();
else if (a->getType() == typeid(dog))
bark();
};
请注意,您应该将上述示例视为伪代码。对于最佳实践,您需要查找模式。此外,奇怪的重复模板模式也可以在第二种方法中使用,或者可以轻松地从第三种方法中删除。在这些情况下,这只是为了方便。
您可以使用虚函数来实现:
class animal{
public:
virtual ~animal() {}
virtual void do_thing() = 0;
};
class dog: public animal{
public:
void do_thing() override { std::cout << "I'm a dog" << std::endl; }
};
class fish: public animal{
public:
void do_thing() override { std::cout << "I'm a fish" << std::endl; }
};
然后
void functionTest(animal& a){
a.do_thing();
}
作为替代方案,如果您想避免拥有许多虚拟功能,您可以使用访客模式
让我强烈敦促你不要做你在这里做的事情,并遵循每个人都给出的非常明智的建议来使用多态性(例如虚函数(。您概述的方法可以工作,但它与语言提供的工具背道而驰。你试图做的正是为什么语言具有虚拟功能。
使用你的方法,如果你添加一个新的animal
子类,那么你还必须更改function_test()
,function_test()
正在做编译器无论如何都会为虚函数做的事情,但以一种更笨拙和低效的方式。
使用虚函数,您所要做的就是在新子类中实现do_something()
,编译器负责其余的工作。
不要为此使用dynamic_cast<>()
。这不是它的用途。
考虑将此"开关"实现为虚拟函数。
如果不希望这样做,可以使用示例中的dynamic_cast
,也可以使用 typeid 运算符计算typeid
到实现do_something
代码的函数的结果的映射。
但是,我不建议这样做,因为您最终只会得到一个手动编码的 vtable。最好使用虚函数并让编译器生成映射。
对于其他阅读,我推荐Herb Sutter的文章类型推断与静态/动态类型。他提到了Boost变体和Boost任何变体,这可能是您问题的可能替代方案。
Stroustrup 的"经典"类型开关可能适合您的需求:https://parasol.tamu.edu/mach7/https://parasol.tamu.edu/~yuriys/pm/
基本上,它将允许您使用三种不同的实现之一来执行基于obect类型的开关案例。
- 为什么使用 "this" 指针调用派生成员函数?
- 具有奇怪重复模板模式的派生类中的成员变量已损坏
- 如何理解C++标准N3337中的expr.const.cast子句8
- 在派生函数中指定void*参数
- 如何通过派生类函数更改基类中的向量
- 如何委托派生类使用其父构造函数?
- C++Cast运算符过载
- 如何使用单独文件中的派生类访问友元函数对象
- 派生类销毁的最佳实践是什么
- 如何使用基类指针引用派生类成员
- 派生类是否可以在抽象工厂设计模式中具有数据成员
- 使用基类指针创建对象时,缺少派生类析构函数
- 如何引用基类的派生类?
- 存储模板类型以强制转换回派生<T>
- 需要从 istream 和 ostream 派生 iostream
- 在 C++ 中用派生类型重写成员函数
- 具有多个类、派生类的C++正向声明
- 有没有一种"cleaner"的方法可以在指向基的指针向量中找到派生类的第一个实例?
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 使用派生到基类的 boost 序列化"unregistered void cast"