你有一个动物收容所。避难所可以存储可变数量的动物。你把许多动物(狗和猫)放进了避难所。
然后你告诉员工随机选择并带给你几只动物。你不知道他选择了什么类型的动物。 你告诉他们说话。其中一些是“吠”,一些是“喵”。
重要!狗可以取,猫不能。 如果你确定你已经选择了一只狗它应该能够立即取出(例如没有从动物到狗的向上转播)
如何实现这种逻辑? (最好不要加速::任何)
以下是部分工作示例: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;
}
答案 0 :(得分:1)
编辑:
您可以尝试使用dynamic_cast
将Animal
对象转换为Dog
,然后调用fetch
方法:
Dog *foo = dynamic_cast<Dog*>(shelter.Select(1));
if (foo) {
foo->Fetch();
}
如果dynamic_cast
失败,它将返回null
,因此请确保在使用之前检查对象是否不是null
。有关dynamic_cast
的详细信息,请查看here。
您可以在Animal
界面添加virtual功能:
class Animal {
public:
virtual void speak();
};
此外,根据不相关的说明,您的speak
方法似乎无法修改对象,因此您应该考虑将它们设为const
:
class Animal {
public:
virtual void speak() const;
};
您可以找到有关const-correctness here的更多信息。
答案 1 :(得分:1)
Aliou
注意speak
应该在virtual
中声明Animal
,否则层次结构相当无用,换句话说,就没有多态性。
使用Animal
测试Dog
是否为dynamic_cast<Dog*>
(并同时向上转播)是一个需要考虑的选项。不漂亮,但它确实有效。
Dog *dog = dynamic_cast<Dog*> shelter.Select(1);
if (dog) dog->Fetch();
(dynamic_cast
指针从不抛出,正如其他人建议的那样......)
另一个解决方案是在virtual
中定义Fetch
Animal
,也许作为NOP({}
),因此您不必在动物中定义它不要拿。
答案 2 :(得分:0)
根据要求,我发表评论作为答案。完整的来源位于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();
答案 3 :(得分:0)
你没有要求雇员只返回可以取的动物,因此你必须检查(施放)每只动物可以取的动物。
另一种方法是向动物添加一个虚拟提取功能,除了狗之外什么都不做。