可以具有不同基成员实现的类的最佳实现

Posted

技术标签:

【中文标题】可以具有不同基成员实现的类的最佳实现【英文标题】: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; 是不同的类型。 【参考方案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,因为它在当前代码中,而不是相反。我将测试这些想法并将其结合回来!

以上是关于可以具有不同基成员实现的类的最佳实现的主要内容,如果未能解决你的问题,请参考以下文章

c#核心基础--类的继承

指向具有私有构造函数的类的类成员的指针

详解C++中基类与派生类的转换以及虚基类

在 C++ 中虚拟基类的两个实现之间共享方法

抽象类和类成员

C#中接口和抽象类的区别