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

C++ Specialize Inherited Template in Derived Class

本文关键字:继承 专门化 派生 C++      更新时间:2023-10-16

我正在尝试编写一个程序,其中派生的ServiceWorker 类(如消防员(可以"面对"从类事件(火灾,伤害,抢劫(派生的对象。对抗将返回一个布尔值,即它是否成功。例如,面对火灾的消防员会成功,但面对抢劫的消防员不会。ServiceWorker 将跟踪对抗和成功对抗的数量,并有一个对抗方法来确定对抗是否成功。

我想使用特征来存储 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(); }
};
在我看来

,如果你利用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<T> 的问题,即使您通过 Firefighter 对象调用它。一个简单的解决方法是将confront的定义复制到每个派生类中。