C ++在派生类中专门化继承模板
Posted
技术标签:
【中文标题】C ++在派生类中专门化继承模板【英文标题】:C++ Specialize Inherited Template in Derived Class 【发布时间】:2016-04-06 22:26:27 【问题描述】:我正在尝试编写一个程序,其中 ServiceWorker 的派生类(例如 Firefighter)可以“对抗”派生自类 Incident(火灾、伤害、抢劫)的对象。对抗将返回是否成功的布尔值。例如,面对火灾的消防员会成功,但面对抢劫的消防员不会成功。 ServiceWorker 将跟踪对抗和成功对抗的数量,并有一个对抗方法来确定对抗是否成功。
我想使用特征来存储 ServiceWorker 的每个派生类在其类定义中可以面对的内容。但是,在 ServiceWorker 中,面对方法创建了特征类,但我想将其专门用于其派生类,因此每个派生类只知道它可以面对什么。
class Incident ;
class Fire : Incident ;
class Robbery : Incident ;
class Injury : Incident ;
class ServiceWorker
public:
ServiceWorker() : ratio(0), num_success(0), num_confronts(0)
template <typename U>
struct can_confront
static const bool result = false;
;
double successRatio()
if(ratio)
return ratio;
else
throw;
template <typename T>
void confront(T incident)
if(can_confront<T>::result)
num_success++;
num_confronts++;
ratio = num_success / num_confronts;
protected:
double ratio;
unsigned int num_success;
unsigned int num_confronts;
;
class Firefighter : public ServiceWorker
public:
template <>
struct can_confront<Fire>
static const bool result = true;
;
;
编辑
所以我设法弄明白了。我去掉了模板,把 face 变成了虚拟的,所以制作一个 ServiceWorker 的派生类只需要重新定义虚拟函数并使用 ServiceWorker::confront。我还添加了 faces_success() 和 calc_ratio() 以更轻松地添加新的 ServiceWorker。我让 Firefighter::confront() 采用 FirefighterIncident,它继承自 Incident。这样,为 Firefighter 添加新事件会很容易,因为它们只需要从 FirefigerIncident 继承即可。
class Incident ;
class FirefighterIncident : public Incident ;
class Fire : public FirefighterIncident ;
class RescueCat : public FirefighterIncident ;
class ServiceWorker
public:
ServiceWorker() : ratio(0), num_success(0), num_confronts(0)
double successRatio()
if(num_confronts != 0)
return ratio;
else
std::cout << "Can't divide by zero in ratio!" << std::endl;
throw;
virtual void confront(const Incident&)
num_confronts++;
calc_ratio();
protected:
double ratio;
unsigned int num_success;
unsigned int num_confronts;
void calc_ratio()
ratio = num_success / (double) num_confronts;
void confront_success()
num_success++;
num_confronts++;
calc_ratio();
;
class Firefighter : public ServiceWorker
public:
using ServiceWorker::confront;
virtual bool confront(const FirefighterIncident&) confront_success();
;
【问题讨论】:
不,您不能这样做,您可以在派生类中更改的唯一内容是虚函数实现及其返回类型(协变)。由于confront
不是虚拟的,所以我不知道派生类的存在。
您需要双重调度才能拥有void confront(ServiceWorker&, const Incident&)
。
@Jarod42 " to have double dispatch" 如果需要运行时多态性,即。
【参考方案1】:
在我看来,如果您利用std::true_type
和std::false_type
,事情会变得更清晰。在基类中,
class ServiceWorker
public:
template <typename U>
struct can_confront: std::false_type ;
...
在派生类中,
class Firefighter: public ServiceWorker
public:
template<typename U>
struct can_confront: ServiceWorker::template can_confront<U> ;
...
请注意,我在派生类中重新定义了can_confront
(通过继承),这样我就可以在不专门化ServiceWorker::can_confront
的情况下专门化它。为此,只需添加
template<>
struct Firefighter::can_confront<Fire>: std::true_type ;
在类定义之外。一旦if
语句被替换为
confront
模板方法就会起作用
if(can_confront<T>::value)
然而,请记住,您仍然会遇到confront
始终使用ServiceWorker::can_confront<T>
的问题,即使您通过Firefighter
对象调用它也是如此。一个简单的解决方法是将confront
的定义复制到每个派生类中。
【讨论】:
这些可能是不错的改进,但与问题的主旨无关。将模板复制到派生的 cassess 不会有任何效果。 @n.m.除了工作代码(OP 的代码无法编译)和他正在寻找的专业化程序之外的任何东西。在我的理解中,问题的要点正是针对多个派生类的can_confront
的专业化。多态性是不可能的,因为confront
不能成为虚拟的,但它可以实现,例如通过重载,如果真的想要的话。
是的,最初,我使用多态性使其工作,并且每个事件都有一个数字代码。当事件传递给 ServiceWorker 时,在面对()中检查了数字代码。我认为这确实是一种草率的技术,但我认为我可以使用特征类来改进它。这样做的目的是保持相同的多态性和继承能力,同时消除对数字代码的需求。以上是关于C ++在派生类中专门化继承模板的主要内容,如果未能解决你的问题,请参考以下文章