简体   繁体   English

如何管理基础class中不同类型的数据?

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

My goal is to separate data from various implementations.我的目标是将数据与各种实现分开。 I don't want my things to know what actual subclass it is they are working with, either way around.我不希望我的东西知道他们正在使用的实际子类,无论哪种方式。 To make things perform only a single task with minimal information.让事情只用最少的信息执行一项任务。

I'll throw some code in your eyes first.我会先把一些代码放在你的眼睛里。

// 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();
}

The motivation behind this is acquisition of all data from a single interface.这背后的动机是从单个界面获取所有数据。 I need to be able to add functionality like the GuiTextBoxComponent, without #include "Derived1.h" in its header.我需要能够添加类似 GuiTextBoxComponent 的功能,而在其 header 中没有#include "Derived1.h"

The challenge with this design is that the Model interface needs to implement all types required from anywhere in the program.这种设计的挑战在于 Model 接口需要实现程序中任何地方所需的所有类型。

How would you extend the types provided?您将如何扩展提供的类型?

Is there some other design that could be used to achieve similar results?是否有其他设计可用于实现类似结果?

Generally, I think this is an XY problem but here is how you can beautify your code a bit.一般来说,我认为这是一个 XY 问题,但这里是你可以如何美化你的代码的方法。 First, I implemented two interfaces: Getter and Setter like:首先,我实现了两个接口: 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;
        }
    }
};

Here I used CRTP, ie static polymorphism.这里我使用了CRTP,即static多态性。 Then implementation of your derived classes is a bit simpler:然后派生类的实现会更简单一些:

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;
    }
};

Finally, since we were using CRTP, there is no need for creating std::unique_ptr .最后,由于我们使用的是 CRTP,因此无需创建std::unique_ptr Code that's using above classes could look like:使用上述类的代码可能如下所示:

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);
}

Check out the DEMO .查看演示

PS Note the usage of enum class instead of plain enum . PS注意使用enum class而不是普通的enum

Take a look at this CppCon's talk about Solid principles.看看这个CppCon 关于 Solid 原则的演讲。 Your code might be a good example to apply those principles to.您的代码可能是应用这些原则的一个很好的例子。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 一个管理多维数组的类! 如何管理单元中的不同数据类型? - A class to manage multidimensional array! How can I do to manage different data types in the cells? 如何在一个类中正确管理2个不同类型的容器? - How to correctly manage 2 containers of different types in a class? 如何构造派生类对不同数据类型进行操作的基类 - How to structure base class where derived classes operate on different data types 用不同的返回类型覆盖基类函数 - Overriding a base class function with different return types 如何允许子类具有公共基类,但在其方法中接受不同类型的参数 - How to allow subclasses to have a common base class but accept different types of arguments in their methods 如何使虚拟函数根据其所属的类返回不同类型,而不在Base中包含虚拟实现? - How to have virtual functions that returns different types based on the class to which it belongs without including dummy implementation in Base? 当基类和子类具有相同的对象名称但类型不同时,如何访问子类的数据成员。 在C ++中 - How to access child class's datamember when both base and child class have same object name but different types. in C++ 基础/派生模板类类型 - Base/Derived template class types 如何在一个向量中管理基类实例和派生类实例? - How to manage base-class instances and derived-class instances in one vector? 不同类型的班级 - Class with different types
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM