在一个数据结构中存储多态类型
Storing polymorphic types in one data structure
你有一个动物收容所。庇护所可以存储可变数量的动物。你把许多动物(狗和猫)放进了收容所。
然后你告诉员工随机选择并带给你一些动物。你不知道他选择了什么类型的动物。你告诉他们说话。其中一些会"吠叫",有些会"喵"。
重要!狗可以取,猫不能。如果您确定您选择了一只狗,它应该能够立即获取(例如,无需从动物转换为狗)
这种逻辑怎么实现?(最好没有提升::任何)
下面是一个部分工作的示例:http://ideone.com/kR4788
#include <iostream>
#include <map>
using namespace std;
class Animal {};
class Shelter {
private:
std::map<int, Animal*> animals;
public:
void Add(Animal* animal) {
animals[animals.size()] = animal;
};
Animal* Select(int index) {
return animals[index];
}
};
class Dog: public Animal {
public:
void Speak() { cout << "bark" << endl; }
void Fetch() {}
};
class Cat: public Animal {
public:
void Speak() { cout << "meow" << endl; }
};
Shelter shelter;
int main() {
shelter.Add(new Cat());
shelter.Add(new Dog());
// I'd like to make it work like this
//
// shelter.Select(0)->Speak(); /* meow */
// shelter.Select(1)->Speak(); /* bark */
//
// Like below but without upcasting to given animal
((Cat*) shelter.Select(0))->Speak();
((Dog*) shelter.Select(1))->Speak();
// I know under index 1 is a Dog so it can fetch!
//
// shelter.Select(1)->Fetch(); /* no segfault */
//
// Like below but without upcasting to given animal
((Dog*) shelter.Select(1))->Fetch();
return 0;
}
编辑:
可以尝试使用 dynamic_cast
将Animal
对象强制转换为Dog
,然后调用 fetch
方法:
Dog *foo = dynamic_cast<Dog*>(shelter.Select(1));
if (foo) {
foo->Fetch();
}
如果dynamic_cast
失败,它将返回null
因此请确保在使用对象之前检查对象是否未null
。有关dynamic_cast
的更多信息,请查看此处。
您可以将虚拟函数添加到Animal
界面:
class Animal {
public:
virtual void speak();
};
此外,在不相关的说明中,您的speak
方法似乎没有修改对象,因此您应该考虑将它们放在const
:
class Animal {
public:
virtual void speak() const;
};
您可以在此处找到有关恒定正确性的更多信息。
Aliou
注意到的speak
应该在Animal
中声明为virtual
,否则层次结构是相当无用的,或者换句话说,没有多态性。
测试Animal
是否是具有dynamic_cast<Dog*>
的Dog
(同时是向上转换)是一个需要考虑的选项。不漂亮,但它有效。
Dog *dog = dynamic_cast<Dog*> shelter.Select(1);
if (dog) dog->Fetch();
(dynamic_cast
指针永远不会像其他人建议的那样抛出......
另一种解决方案是在Animal
中定义virtual
Fetch
,也许是NOP({}
),这样你就不必在不获取的动物中定义它。
根据要求,我将我的评论作为答案。完整的源代码在 Ideone 中:
在动物类中:
class Animal {
public:
virtual void Speak() const = 0;
virtual void Fetch() const { cout << "This animal can't fetch" << endl;};
virtual ~Animal(){ }
};
需要虚拟析构函数来确保为派生自基类的对象调用正确的析构函数。如果没有虚拟析构函数,将仅调用基类析构函数,而不调用派生对象的析构函数。
在狗中:
void Fetch() const { cout << "fetch" << endl; }
并且主要:
shelter.Select(0)->Speak();
shelter.Select(1)->Speak();
shelter.Select(0)->Fetch();
shelter.Select(1)->Fetch();
您没有要求员工只归还可以取物的动物,因此您必须检查(投射)每只动物可以取物。
另一种方法是为动物添加一个虚拟获取功能,除了狗之外,它什么都不做。
- 多态性和功能结合
- 具有默认模板参数的多态类的模板推导失败
- 找不到成员对象:没有名为get_event()的成员,也处理多态性和向量
- 多态二进制函数
- 访问存储在向量C++中的结构的多态成员
- 使用取消引用的指针的多态性会产生意外的结果.为什么?
- C++ 在堆栈中包含多态属性的类对象存储
- 当依赖关系和依赖关系都是多态时,在哪个继承级别存储依赖关系指针?
- 为什么使用 Boost.Intrusive 容器来存储多态对象是可以的?
- 将多态对象存储在unordered_set中
- 多态类型的连续存储
- 由支持多态性的值池存储,如何使用智能指针
- 多态性和对象存储
- 是否可以将多态性类存储在共享内存中
- 如何存储多态闭包
- 我可以使用多态性将不同的对象存储在具有C++的数组中吗?
- 多态数据存储的替代方案
- 使用多态性是在一个容器中存储不同数据类型的好方法吗?
- 在一个数据结构中存储多态类型
- c++继承,多态和存储对象