如何处理一个子类有方法,而另一个没有方法的子类?

How to handle one subclass have a method, while another subclass that doesn't have it?

本文关键字:有方法 子类 另一个 一个 何处理 处理      更新时间:2023-10-16

我有一个关于接口的问题,比如说:

class IAnimal
{ ...
Public:
virtual void makeSound() = 0;
};
class Cat : public IAnimal
{  ...
void makeSound() { std::cout << "purr" << std::endl; }
};
class Dog : public IAnimal
{  ...
void makeSound() { std::cout << "bark" << std::endl; }
};
class AnimalFactory
{
std::shared_ptr<IAnimal> createAnimal(animalType type)
{  
std::shared_ptr<IAnimal> animal;
switch(type)
{ case animal_type::cat: animal = std::shared_ptr<Cat>(); break; 
case animal_type::dog: animal = std::shared_ptr<Dog>(); break; 
… }
return animal;
}
};
class App
{ ...
std::shared_ptr<IAnimal> _animal;
AnimalFactory::animal_type type;
void haveCat()
{ ...
type = AnimalFactory::animal_type::cat;
_animal = AnimalFactory.createAnimal(type);
_animal->makeSound();
...
} 
};

现在,我需要这只猫来抓老鼠void catchMouse(){std::cout<<"抓老鼠";}

void haveCat()
{ ...
type = AnimalFactory::animal_type::cat;
_animal = AnimalFactory.createAnimal(type);
_animal->makeSound();
// catchMouse();
...
}

有几种可能的解决方案,但看起来都不太好。

  1. 在IAnimal中添加一个方法,然后在使用AnimalFactory创建一个猫之后,我可以从IAnimal调用catchMouse()方法。但老鼠不适合所有动物,狗不适合老鼠。在IAnimal中添加一个方法会污染接口、气味代码
  2. 在Cat中添加一个公共方法catchMouse(),并在haveCat()方法中将_animal强制转换为Cat。

    {
    _cat = std::dynamic_pointer_cast<Cat>(AnimalFactory.createAnimal(type));
    _cat->makeSound();
    _cat->catchMouse();
    }
    

    但是有一个动态的演员阵容,不好,对吧?

  3. 让Cat实现IAnimal接口,还有一个关于Mouse的接口,但AnimalFactory只返回std::shared_ptr,我们不能在IAnimal中调用catchMouse。

我在这里说的是,一个子类中有一个公共方法,但另一个子类没有,如果我们使用工厂,如何设计它。请不要回复,让狗抓兔子,然后在IAnimal中添加一个catch()方法,这样,猫可以抓老鼠,狗可以抓兔子。

解决这个问题的好办法是什么?谢谢

我认为你实际上不能从shared_ptr转换为Cat,是吗?因此,在不了解您的代码库的情况下,我编写了一个小型测试程序

#include <memory>
#include <string>
#include <iostream>
class IAnimal
{ 
public:
virtual void makeSound(){}
};
class Cat : public IAnimal
{  
public:
virtual void makeSound() { std::cout << "purr" << std::endl; }
void catchMice(void){
std::cout<<"mouse catchedn";
}
};
class Dog : public IAnimal
{  
virtual void makeSound() { std::cout << "bark" << std::endl; }
};
int main(int argc,char** argv){
Cat* c = new Cat;
std::shared_ptr<IAnimal> s(c);
//you've basically got something of this sort don't you?
s->makeSound();
(static_cast<Cat*>(s.get()))->catchMice();
return 0;
}

那应该是你想要的。我想你可能想把makeSound(void)作为一个虚拟函数。

我想,处理这个问题的方法是您的解决方案2的变体:用特殊的方法制作一个特定的接口ICatcher,并执行以下操作:

AnimalFactory::animal_type type = AnimalFactory::animal_type::cat;
std::shared_ptr<IAnimal> animal = myAnimalFactory.createAnimal(type);
(dynamic_cast<ICatcher*>(animal.get()))->catch();

但在这里,您应该确保dynamic_cast会成功,或者为此提供额外的检查。

也许,您也会对超级接口IUnknown及其QueryInterface方法如何在COM中解决这个问题感兴趣。可以实现该体系结构的本地版本。