为了演示,想象我有一些动物类,每个都来自一个“动物”类,每个都“知道”它们是什么类型,并且每个都具有某种独特的能力:
enum class animal_type { antelope, bear, cat };
class animal
{
};
class antelope : public animal
{
public:
static const animal_type type = animal_type::antelope;
void run() { std::cout << "antelope runs\n"; };
};
class bear : public animal
{
public:
static const animal_type type = animal_type::bear;
void roar() { std::cout << "bear roars\n"; };
};
class cat : public animal
{
public:
static const animal_type type = animal_type::cat;
void meow() { std::cout << "cat meows\n"; };
};
现在,我希望能够根据他们的类型检索动物:
class animal_getter
{
public:
animal& get(animal_type t)
{
static antelope s_antelope;
static bear s_bear;
static cat s_cat;
switch (t)
{
case animal_type::antelope:
return s_antelope;
case animal_type::bear:
return s_bear;
case animal_type::cat:
return s_cat;
}
}
};
最后,让实际的动物类型回来更好,使调用语法更好:
template<typename T>
T& get()
{
return static_cast<T&>(get(T::type));
}
现在我可以这样写:
animal_getter ag;
ag.get<antelope>().run();
而不是更多的人:
animal_getter ag;
static_cast<antelope&>(ag.get(animal_type::antelope)).run();
我希望这没有什么不合理的.但是现在我希望能够对动物进行单元测试,所以理想情况下可以伪造animal_getter类(想象实际的实现访问数据库或者单元测试中你不想要的东西,因此假的) .因此,为’animal getter’类定义一个接口,然后创建一个实现该接口的假的将是很好的.这就是问题,可以编写这个界面吗?这不会编译:
struct IAnimalGetter
{
virtual template<typename T> T& get() = 0;
};
是否可以挽救这个想法,或者模板函数永远不会被声明为虚拟的,以便定义包含它们的接口?
如果这个想法不是首发,那么这个问题何时开始出错?是在编写模板函数时进行自己的投射吗?我是否应该停止返回动物对象然后让调用者对演员负责?
最佳答案 模板和强制类型转换和类型标记似乎在声明的用例中没有任何用处(获取动物然后立即利用其独特的特征).
antelope& get_antelope();
bear& get_bear();
cat& get_cat();
这就是所需要的.
get_antelope().run();
get_cat().meow();
如果需要,这些功能可以是独立的或成员的,虚拟的.每个返回类型需要一个函数.这与每个返回类型的switch语句中的一个案例没有太大区别,并且在某些方面优于它.
如果由于某些未指明的原因,您确实需要功能模板,则可以基于普通函数定义一个.
template <class A>
A& get_animal();
template<> antelope& get_animal<antelope>() { return get_antelope(); }
template<> bear& get_animal<bear>() { return get_bear(); }
template<> cat& get_animal<cat>() { return get_cat(); }