【问题标题】:Best implementation for a class that can have different base member implementations可以具有不同基成员实现的类的最佳实现
【发布时间】:2020-01-17 11:33:18
【问题描述】:

我想要一个子类Handler 来处理多个回调并将数据从一个类传输到另一个类。但是,基类B1B2 可以对其成员有不同的实现。

下面是实现我想要的行为的方法。我认为应该有更好的方法,但无法弄清楚。

// Example program
#include <iostream>
#include <string>

template <class T>
class IBase
{
    public:
        IBase()
        {
            object = new T(*this);    
        };

        ~IBase()
        {
            delete object;
        }

        virtual void ValidateCallback()
        {
        };

        void RxCallback()
        {
           object->RxCallback();
        };

        void Send()
        {
            object->Send();
        };

       T* object;
};

class C1
{
    public:
        virtual void RxCompleteCallback() = 0;

        void RxParse()
        {
            std::cout << "Parse C1" << std::endl;
            RxCompleteCallback();
        };
};

class C2
{
    public:
        virtual void RxCompleteCallback() = 0;

        void RxParse()
        {
            std::cout << "Parse C2" << std::endl;
            RxCompleteCallback();
        };
};

class B1 : public C1
{
    public:
        B1(IBase<B1> &handler )
        {
           ihandler = &handler;
        };

        void DoSomething()
        {
            std::cout << "DoSomething B1" << std::endl;
            ihandler->ValidateCallback();
        };

        void RxCompleteCallback() override
        {
            std::cout << "DoSomething other than B2" << std::endl;
            std::cout << "RxCompleteCallback" << std::endl;
        };

        void RxCallback()
        {
            RxParse();
        };

        void Send()
        {
            DoSomething();
        };

        IBase<B1> * ihandler;
};

class B2 : public C2
{
    public:
        B2(IBase<B2> &handler )
        {
           ihandler = &handler;
        };

        void DoSomething()
        {
            std::cout << "DoSomething B2" << std::endl;
            ihandler->ValidateCallback();
        };

        void RxCompleteCallback() override
        {
            std::cout << "DoSomething other than B1" << std::endl;
            std::cout << "RxCompleteCallback" << std::endl;
        };

        void RxCallback()
        {
            RxParse();
        };

        void Send()
        {
            DoSomething();
        };

        IBase<B2> * ihandler;
};

class Validate
{
    public:
        void CalculateValidation()
        {
            std::cout << "Calculate validation" << std::endl;
        };
};

template <class T>
class Handler : public IBase<T>, public Validate
{
    public:
        void ValidateCallback() override
        {
            std::cout << "ValidateCallback" << std::endl;
            CalculateValidation();
        };

        void Receive()
        {
            IBase<T>::RxCallback();
        };

        void Send()
        {
           IBase<T>::Send();
        }

};

int main()
{
    Handler<B1> handler1;
    handler1.Receive();
    handler1.Send();
    std::cout << std::endl;
    Handler<B2> handler2;
    handler2.Receive();
    handler2.Send();
}

输出:

Parse C1
DoSomething other than B2
RxCompleteCallback
DoSomething B1
ValidateCallback
Calculate validation

Parse C2
DoSomething other than B1
RxCompleteCallback
DoSomething B2
ValidateCallback
Calculate validation

【问题讨论】:

  • 您的IBase 类实现似乎泄漏了内存。我认为你把事情复杂化了。但老实说,我根本不明白你想要达到什么目的。
  • 你能描述一下你想用这个设计解决什么问题吗?
  • 简而言之:我想实现多种通信协议。 Handler 类实现所有协议所需的通用功能。但是BC 类的方法实现取决于协议的种类。基本上我想要一个像class Handler : public T 这样的类签名,其中T 可以是protocol1Handler 或protocol2Handler。但这种签名是不可能的。
  • 这让我想起了策略设计模式,只是你同时有各种策略,必须选择正确的一个。
  • 您需要运行时多态性吗?从您的示例中不清楚 - 请注意 Handler&lt;B1&gt;Handler&lt;B2&gt; 是不同的类型。

标签: c++ c++11 c++17


【解决方案1】:

在 C++ 中有几种方法可以做到这一点。很难说最好的方法是什么,这取决于你将如何使用它,而且你给出的例子太简单了,无法推荐具体的方法。通常,我会说你想从Handler 派生你的协议特定类,而不是相反,所以你会写:

class Handler {
public:
    virtual void Receive() {};
    virtual void Send() {};
};

class B1: public Handler {
    virtual void Receive() {
        ...
    }

    virtual void Send() {
        ...
    }
};

int main() {
    B1 handler1;
    handler1.Receive();
    ...
}

这里的主要问题是你需要在这里使用virtual成员函数,否则基类不知道要调用哪个派生类的实现。但它确实允许您将 Handler * 作为参数传递给另一个函数,然后该函数将与任何派生类一起工作,而无需任何模板。

另一种选择是使用curiously recurring template pattern,如下所示:

template <typename T>
class Handler {
    void Receive() {
        static_cast<T*>(this)->Receive();
    }

    void Send() {
        static_cast<T*>(this)->Send();
    }
};

class B1: public Handler<B1>
{
    void Receive() {
        ...
    }

    void Send() {
        ...
    }
};

int main() {
    B1 handler1;
    handler1.Receive();
    ...
}

这避免了虚方法。 它也与您的class Handler 非常相似,但它的优点是不需要T *object 成员变量。

【讨论】:

  • 感谢您的帮助。至于第一个例子。这也是我通常会如何实现它的方式。但是,我必须处理一些遗留代码。稍后我会看看我是否可以重写它仍然与旧代码兼容。至于第二个例子。在我的帖子之前,我也在尝试这个,但无法让它正确地用于向下和向上调用。我认为这是因为我的Handler 继承自B1,因为它在当前代码中,而不是相反。我将测试这些想法并将其结合回来!
猜你喜欢
  • 2017-04-10
  • 1970-01-01
  • 2013-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-04
相关资源
最近更新 更多