C ++专门派生类中的继承模板

时间:2016-01-02 23:59:27

标签: c++ templates inheritance template-specialization

我试图编写一个程序,其中ServiceWorker的派生类(如消防员)可以“面对”#34;派生类偶然事件(火灾,伤害,抢劫)。对抗会返回一个布尔值,表示它是否成功。例如,面对火灾的消防队员将获得成功,但面对抢劫的消防员则不会。 ServiceWorker将跟踪对抗次数和成功对抗的数量,并采用对抗方法来确定对抗是否成功。

我想使用traits来存储每个派生类ServiceWorker在其类定义中可以面对的内容。但是,在ServiceWorker中,confront方法创建了traits类,但我想在其派生类中对其进行特化,因此每个派生类只知道它可以面对的是什么。

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;
    };
};

修改

所以我设法搞清楚了。我摆脱了模板并且面对虚拟,因此创建一个派生类的ServiceWorker只需要重新定义虚函数并使用ServiceWorker :: confront。我还添加了confront_success()和calc_ratio(),以便更轻松地添加新的ServiceWorkers。我让Firefighter :: confront()接受了FirefighterIncident,它继承自Incident。这样,为Firefighter添加新事件很容易,因为他们只需从FirefigherIncident继承。

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(); }
};

1 个答案:

答案 0 :(得分:0)

在我看来,如果您利用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 { };

外部类定义。 confront语句替换为

后,if模板方法将起作用
if(can_confront<T>::value)

然而,请记住,即使您通过confront对象调用它,您仍然会遇到ServiceWorker::can_confront<T>始终使用Firefighter的问题。一个简单的解决方法是将confront的定义复制到每个派生类中。