选择覆盖方法的基类

时间:2016-07-08 16:41:39

标签: c++ inheritance multiple-inheritance observer-pattern

鉴于以下内容:

class Observer
{
    public:
        virtual void Observe(Parameter p) = 0;
};

template<size_t Tag>
class TaggedObserver : public Observer { };

class Thing : public TaggedObserver<0>, TaggedObserver<1>
{
    public:
        virtual void Observe(Parameter p) override;
};

Thing::Observe会覆盖TaggedObserver<0>::ObserveTaggedObserver<1>::Observe 有没有办法为每个基类提供不同的覆盖?
基本原理:我希望类能够观察两个相同类型的通知源,每个源具有不同的操作,而不必求助于在参数中传递源,然后在if / {{1 }}

2 个答案:

答案 0 :(得分:3)

为了提供不同的覆盖,您需要定义不同的派生类,例如:

class Observer
{
public:
    virtual void Observe(Parameter p) = 0;
};

template<size_t Tag>
class TaggedObserver : public Observer
{
};

class TaggedObserverZero : public TaggedObserver<0>
{
public:
    virtual void Observe(Parameter p)
    {
        // do something ...
    }
};

class TaggedObserverOne : public TaggedObserver<1>
{
public:
    virtual void Observe(Parameter p)
    {
        // do something else ...
    }
};

但是,如果您希望Thing::Observe()先收到Parameter并将其发送到相应的基类,则无法使用if语句(或等效语句)在Thing中,因为它继承了TaggedObserver::Observe()的多个副本,需要决定调用哪个副本:

class Thing : public Observer, TaggedObserverZero, TaggedObserverOne
{
public:
    virtual void Observe(Parameter p)
    {
        if (some condition)
            TaggedObserverZero::Observe(p);
        else if (some other condition)
            TaggedObserverOne::Observe(p);
    }
};

或者,你无条件地打电话给他们,让他们弄清楚该怎么做:

class TaggedObserverZero : public TaggedObserver<0>
{
public:
    virtual void Observe(Parameter p)
    {
        if (some condition)
            // do something ...
    }
};

class TaggedObserverOne : public TaggedObserver<1>
{
public:
    virtual void Observe(Parameter p)
    {
        if (some other condition)
            // do something else ...
    }
};

class Thing : public Observer, TaggedObserverZero, TaggedObserverOne
{
public:
    virtual void Observe(Parameter p)
    {
        TaggedObserverZero::Observe(p);
        TaggedObserverOne::Observe(p);
    }
};

答案 1 :(得分:2)

TaggedObserver中实现它们(如果需要,提供明确的专业化),例如:

class Observer {
public:
    virtual void Observe(Parameter p) = 0;
};

template<size_t Tag>
class TaggedObserver : public Observer {
public:
    void Observe(Parameter p) override { }
};

template<std::size_t... I>
class Thing : public TaggedObserver<I>... {
public:
    Thing(): TaggedObserver<I>{}... {}

    template<std::size_t N>
    void Observe(Parameter p) {
        TaggedObserver<N>::Observe(p);
    }
};

然后,您可以将Thing专门设为Thing<0, 1>并使用thing.Observe<1>(p)调用正确的函数。

修改

此编辑的目的是显示一个新的示例代码,即使稍作修改,也可能与上面的代码差不多。
我希望这可以帮助OP。基本思想是结合CRTP习语,虚拟方法和继承。

class Observer {
public:
    virtual void Observe(Parameter p) = 0;
};

template<template T, size_t Tag>
class TaggedObserver : public Observer {
public:
    void Observe(Parameter p) override {
        T *t = static_cast<T*>(this);
        // Now use whatever you want from T, that is Thing in this example
    }
};

template<std::size_t... I>
class Thing : public TaggedObserver<Thing<I...>, I>... {
     template<std::size_t J>
     friend class TaggedObserver<Thing<I...>, J>;

public:
    Thing(): TaggedObserver<Thing<I...>, I>{}... {}

    template<std::size_t N>
    void Observe(Parameter p) {
        TaggedObserver<Thing<I...>, N>::Observe(p);
    }
};

请注意,friend声明允许TaggedObserver访问Thing的私人成员。

这样,ObserveTaggedObserver的实施可以按照评论中的要求访问Thing中的公共成员,受保护成员和私有成员。

最后,如果需要,您可以专门设置TaggedObserver,以便为Observe提供不同的实施方案。
举个例子:

template<template T, size_t Tag>
class TaggedObserver;

template<template T>
class TaggedObserver<T, 0>: public Observer {
public:
    void Observe(Parameter p) override {
        T *t = static_cast<T*>(this);
        // Now use whatever you want from T, that is Thing in this example
        // Put here the code of the specialization for Tag 0
    }
};

template<template T>
class TaggedObserver<T, 1>: public Observer {
public:
    void Observe(Parameter p) override {
        T *t = static_cast<T*>(this);
        // Now use whatever you want from T, that is Thing in this example
        // Put here the code of the specialization for Tag 1
    }
};