c++ - 如何在面向对象语言中打开子类型?
问题描述
我主要来自函数式语言背景,我不知道如何在面向对象的语言中很好地完成这种模式。
假设我有一些 Animal 类和子类以及一个 AnimalManager。我想要一个 AnimalManager 上的“add”方法,它具有不同的行为,具体取决于我添加的是猫还是狗。像这样的东西(没有特定的语言):
class Animal
class Cat : Animal
class Dog : Animal
class AnimalManager {
void add(Animal a) {
a match {
case Cat => // do something with cats
case Dog => // do different something with dogs
}
}
}
现在,如果我使用像 C++ 这样不支持以这种方式匹配类型的语言怎么办。我能想到的两个解决方案是:
- 使用 dynamic_cast。但是,有人告诉我应该避免动态转换,因为它会导致运行时错误,所以这可能是不好的做法。
- 使用虚函数。我可以做类似以下的事情(同样没有特定的语言,但你应该明白要点):
class Animal {
virtual void beAdded(AnimalManager am)
}
class Cat : Animal {
void beAdded(AnimalManager am) {
am.doThingsWithCats(this)
}
}
class Dog : Animal {
void beAdded(AnimalManager am) {
am.doThingsWithDogs(this)
}
}
class AnimalManager {
void doThingsWithDogs(Dog d) {
// do something with dogs
}
void doThingWithCats(Cat d) {
// do something with cats
}
void add(Animal a) {
a.beAdded(this)
}
}
这显然非常尴尬并且还有其他问题(现在 Animal 需要了解 AnimalManager?)。
在面向对象语言中执行这种模式的最佳方法是什么?我应该知道这里有一些“设计模式”吗?
解决方案
我建议您提供真实用例而不是隐喻,因为您可能遇到XY 问题。您可以在这里使用 RTTI,还有一个我想详细说明的问题。
不要使用void add(Animal a)
which将您的对象切片为 just Animal
,您将始终得到Animal
而不是派生类Cat
或Dog
. 用于void add(Aniaml& a)
保留对象或使用(智能)指针。
#include <iostream>
class Animal{
public:
// Read Item 7 in Scott Meyers' Effective C++ if you don't know why you need it
#include <iostream>
class Animal{
public:
virtual ~Animal(){};
};
class Cat : public Animal{
};
class Dog : public Animal{
};
class AnimalManager {
public:
#define REF < comment it to see what your code do
#ifdef REF
void add(Animal& a) {
#else
void add(Animal a) {
#endif
using std::cout;
using std::endl;
if(typeid(a) == typeid(Cat)){
cout << "Meow" << endl;
}else if(typeid(a) == typeid(Dog)){
cout << "Bark" << endl;
}else{
cout << "I'm just animal" << endl;
}
}
};
int main()
{
Dog d;
Cat a;
AnimalManager m;
m.add(d);
m.add(a);
}
供参考
Bark
Meow
按值传递
"I'm just animal
"I'm just animal
推荐阅读
- python - Keras incompatible shapes
- c - 我应该如何使用 scanf 从输入中只获取一个字符?
- css - 在 Material-UI 中控制菜单组件的宽度
- c# - 在当前索引上完成 SQL 更新后刷新页面
- json - 从 azure Form Recognizer 可视化来自 JSON 文件的表数据
- reactjs - 使用 axios 在反应中可观察到的 Redux
- javascript - 动态添加带值的输入滑块
- actionscript-3 - 即使在我更改默认文本格式之后,TextField 也会在焦点上切换到原始默认文本格式
- jquery - 使用锁定和解锁列时,如何找出当前正在编辑的单元格在表格的哪个部分?
- c# - SSRS 交付扩展示例或教程或示例