首页 > 解决方案 > 可以具有不同基成员实现的类的最佳实现

问题描述

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

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

// 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

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

解决方案


在 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这里使用成员函数,否则基类不知道要调用哪个派生类的实现。但它确实允许您将 aHandler *作为参数传递给另一个函数,然后该函数将与任何派生类一起工作,而无需任何模板。

另一种选择是使用奇怪的重复模板模式,它​​看起来像:

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成员变量。


推荐阅读