为了演示,假设我有一些动物类,每个都派生自“动物”类,每个都“知道”它们是什么类型,并且每个都具有某种独特的能力:
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 类(想象一下实际实现访问数据库或单元测试中不需要的东西,因此是假的) .因此,最好为“动物 setter/getter ”类定义一个接口(interface),然后创建一个实现该接口(interface)的假对象。而问题来了,这个接口(interface)能不能写?这不会编译:
struct IAnimalGetter
{
virtual template<typename T> T& get() = 0;
};
是否有可能拯救这个想法,或者为了定义包含它们的接口(interface),模板函数永远不会被声明为虚拟的?
如果这个想法是行不通的,那么它是从什么时候开始出错的? 是在编写自己进行转换的模板函数时吗?我是否应该在返回动物对象的地方停下来,然后让调用者负责转换?
最佳答案
虚拟模板函数是不允许的,但是你的模板函数没有逻辑,所以在这种情况下我会使用:
struct IAnimalGetter
{
virtual animal& get(animal_type t) = 0;
template<typename T>
T& get()
{
return static_cast<T&>(get(T::type));
}
};
和:
class animal_getter : public IAnimalGetter
{
public:
animal& get(animal_type t)
{
// implementation
}
};
class mock_animal_getter : public IAnimalGetter
{
public:
animal& get(animal_type t)
{
// mock implementation
}
};
关于c++ - 在 C++ 接口(interface)中声明模板函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45480502/