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

标签 c++ templates inheritance template-specialization

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

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

编辑

所以我设法搞清楚了。我摆脱了模板,将 confront 设置为 virtual,因此创建 ServiceWorker 的派生类只需要重新定义虚函数并使用 ServiceWorker::confront。我还添加了 confront_success() 和 calc_ratio() 以便更轻松地添加新的 ServiceWorker。我让 Firefighter::confront() 采用继承自 Incident 的 FirefighterIncident。这样,为 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_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 { };

类定义之外。 confront一旦if 模板方法将起作用语句替换为

if(can_confront<T>::value)

但是,请记住您仍然面临着 confront 的问题总是使用 ServiceWorker::can_confront<T> ,即使您通过 Firefighter 调用它目的。一个简单的解决方法是复制 confront 的定义进入每个派生类。

关于C++ 专门化派生类中的继承模板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34571996/

相关文章:

android - 如何在 Android NDK 项目中包含二进制文件?

c++ - 为什么switch语句中可以在 'default'下定义变量,而不能在 'case'下定义

c++ - C4711 "function selected for inline expansion"Visual C++ 警告有什么用?

c++ - 结构成员变量不变

c++ - 自定义成员检测器中的模糊调用

java - Android 轻量级 HTML 模板引擎

c++ - 从空类继承时如何解释这个sizeof结果

inheritance - 在 F# 中调用基类显式接口(interface)方法

c++17 有效地将参数包参数与 std::array 元素相乘

visual-studio-2010 - 如何让 F# 推断通用基类型?