【问题标题】:C++ Specialize Inherited Template in Derived ClassC ++在派生类中专门化继承模板
【发布时间】: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&amp;, const Incident&amp;)
  • @Jarod42 " to have double dispatch" 如果需要运行时多态性,即。

标签: c++ templates inheritance template-specialization


【解决方案1】:

在我看来,如果您利用std::true_typestd::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&lt;T&gt; 的问题,即使您通过Firefighter 对象调用它也是如此。一个简单的解决方法是将confront 的定义复制到每个派生类中。

【讨论】:

  • 这些可能是不错的改进,但与问题的主旨无关。将模板复制到派生的 cassess 不会有任何效果。
  • @n.m.除了工作代码(OP 的代码无法编译)和他正在寻找的专业化程序之外的任何东西。在我的理解中,问题的要点正是针对多个派生类的can_confront 的专业化。多态性是不可能的,因为confront 不能成为虚拟的,但它可以实现,例如通过重载,如果真的想要的话。
  • 是的,最初,我使用多态性使其工作,并且每个事件都有一个数字代码。当事件传递给 ServiceWorker 时,在面对()中检查了数字代码。我认为这确实是一种草率的技术,但我认为我可以使用特征类来改进它。这样做的目的是保持相同的多态性和继承能力,同时消除对数字代码的需求。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-24
  • 2013-04-09
  • 1970-01-01
  • 2014-02-04
相关资源
最近更新 更多