簡體   English   中英

如何管理基礎class中不同類型的數據?

[英]How to manage different types of data in the base class?

我的目標是將數據與各種實現分開。 我不希望我的東西知道他們正在使用的實際子類,無論哪種方式。 讓事情只用最少的信息執行一項任務。

我會先把一些代碼放在你的眼睛里。

// Example program
#include <iostream>
#include <string>
#include <memory>
#include <vector>
#include <functional>

class Model
{
    public:
    
    virtual bool set(int p_attrId, int p_value) {return false;}; 
    virtual bool get(int p_attrId, int & p_value) const {return false;};

};

class Derived: public Model
{
    static constexpr int c_classId = 1;
    int value = 1;
    public:
    
    enum EAttrs
    {
        eAttr1 = c_classId * 1000
    };
    
    virtual bool set(int p_attrId, int p_value) override
    {
        switch(p_attrId)
        {
            case eAttr1:
                value = p_value;
                return true;
            
            default:
                return Model::set(p_attrId, p_value);
        }
    }

    virtual bool get(int p_attrId, int & p_value) const override
    {
        switch(p_attrId)
        {
            case eAttr1:
                p_value = value;
                return true;
            
            default:
                return Model::get(p_attrId, p_value);
        }
    }
};

// GuiTextBoxComponent.h

// no includes to any class derived from model

class GuiTextBoxComponent
{
        std::weak_ptr<Model> m_model;
        int m_attrId;
    public:
        void draw()
        {
            auto locked = m_model.lock();
            if(locked)
            {
                int value;
                bool result = locked->get(m_attrId, value);
                if(!result)
                {
                    std::cout << "Failed to get attribute " << m_attrId << "\n";
                    return;
                }
            
                std::cout << "AttrID: " << m_attrId << " Value: " << value << "\n";
            }
            else
            {
                std::cout << "Model is dead\n";
            }
        }
        
        void setSource(std::weak_ptr<Model> p_model, int p_attrId)
        {
            m_model = p_model;
            m_attrId = p_attrId;
        }
};


int main()
{
    std::shared_ptr<Model> model (new Derived);
    GuiTextBoxComponent textbox;
    textbox.setSource(model, Derived::eAttr1);
    textbox.draw();
}

這背后的動機是從單個界面獲取所有數據。 我需要能夠添加類似 GuiTextBoxComponent 的功能,而在其 header 中沒有#include "Derived1.h"

這種設計的挑戰在於 Model 接口需要實現程序中任何地方所需的所有類型。

您將如何擴展提供的類型?

是否有其他設計可用於實現類似結果?

一般來說,我認為這是一個 XY 問題,但這里是你可以如何美化你的代碼的方法。 首先,我實現了兩個接口: GetterSetter ,例如:

enum class EAttrs {
    eAttr1
};

template <typename GetterImpl>
struct Getter {
    bool get(EAttrs const attrId, int& value) {
        switch (attrId) {
        case EAttrs::eAttr1:
            return static_cast<GetterImpl*>(this)->get(value);
        default:
            return false;
        }
    }
};

template <typename SetterImpl>
struct Setter {
    bool set(EAttrs const attrId, int value) {
        switch (attrId) {
        case EAttrs::eAttr1:
            return static_cast<SetterImpl*>(this)->set(value);
        default:
            return false;
        }
    }
};

這里我使用了CRTP,即static多態性。 然后派生類的實現會更簡單一些:

class Derived1 : public Getter<Derived1>, Setter<Derived1> {
    int value = 1;
public:    
    bool set(int p_value) {
        value = p_value;
        return true;
    }

    bool get(int & p_value) {
        p_value = value;
        return true;
    }
};

class Derived2 : public Getter<Derived1>, Setter<Derived1> {
    int value = 2;
public:
    bool set(int p_value) {
        value = p_value;
        return true;
    }

    bool get(int & p_value) {
        p_value = value;
        return true;
    }
};

最后,由於我們使用的是 CRTP,因此無需創建std::unique_ptr 使用上述類的代碼可能如下所示:

template <typename T>
void printInt(Getter<T>& model, EAttrs p_attrId) {
    int value;
    bool result = model.get(p_attrId, value);
    if (!result)
    {
        std::cout << "Failed to get attribute " << static_cast<int>(p_attrId) << "\n";
        return;
    }
    
    std::cout << "AttrID: " << static_cast<int>(p_attrId) << " Value: " << value << "\n";
}

int main()
{
    Derived1 derived1;
    Derived2 derived2;
    
    printInt(derived1, EAttrs::eAttr1);
    printInt(derived2, EAttrs::eAttr1);
}

查看演示

PS注意使用enum class而不是普通的enum

看看這個CppCon 關於 Solid 原則的演講。 您的代碼可能是應用這些原則的一個很好的例子。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM