【问题标题】:How to declare a class member that may be one of two classes如何声明可能是两个类之一的类成员
【发布时间】:2021-11-25 04:59:54
【问题描述】:

我正在处理一个主要不是我创建的项目,但我的任务是为其添加一些功能。目前,有一个设备类有一个成员变量,负责存储有关存储位置的信息,设置如下:

device.hpp

class device {
    public:
        // Stuff
    private:
        // Stuff
        StorageInfo storage_info_;
        // Even more stuff
}

StorageInfo.hpp

class StorageInfo {
    public:
        void initializeStorage();
        void updateStorageInfo();
        int popLocation();
        int peakLocation();
        uint16_t totalSize();
        uint16_t remainingSize();
        // More declarations here
    private:
        //Even more stuff here
}

我的任务是实现不同的存储选项,以便可以在两者之间切换。这个新存储选项具有的信息功能与初始存储选项相同,但检索该信息的实现有很大不同。为了保持干净并在未来几年内更容易维护此应用程序,它们确实需要在两个不同的文件中定义。但是,这会在 device.cpp 内部以及调用 StorageInfo 类的每个其他文件中产生问题。如果我创建两个单独的成员变量,一个用于每种类型的存储,那么我不仅需要插入一百万个不同的 ifelse 语句,而且我有可能在构造函数中遇到初始化问题。相反,我想做的是有一个成员变量有可能保存任一存储选项类。像这样的:

StorageInfoA.hpp

class StorageInfoA: StorageInfo {
    public:
        void initializeStorage();
        void updateStorageInfo();
        int popLocation();
        int peakLocation();
        uint16_t totalSize();
        uint16_t remainingSize();
        // More declarations here
    private:
        //Even more stuff here
}

StorageInfoB.hpp

class StorageInfoB: StorageInfo {
    public:
        void initializeStorage();
        void updateStorageInfo();
        int popLocation();
        int peakLocation();
        uint16_t totalSize();
        uint16_t remainingSize();
        // More declarations here
    private:
        //Even more stuff here
}

device.hpp

class device {
    public:
        // Stuff
    private:
        // Stuff
        StorageInfo storage_info_;
        // Even more stuff
}

device.cpp

//Somewhere in the constructor of device.cpp
if(save_to_cache){
    storage_info_ = StorageInfoA();
} else {
    storage_info_ = StorageInfoB();
}

// Then, these types of calls would return the correct implementation without further ifelse calls
storage_info_.updateStorageInfo();

但是,我知道 cpp 绝对讨厌动态类型的任何东西,所以我真的不知道如何实现它。这种事情甚至可能吗?如果没有,有没有人知道一种类似的方法来实现这一点,它适用于 cpp 的打字规则?

【问题讨论】:

  • 多态很容易解决这个问题。让每个类派生自一个纯虚拟基类,该基类声明了两个派生类都将使用的函数。那么device 可以有一个std::unique_ptr<StorageInfoBaseClass> 作为数据类型。
  • 您在正确的轨道上,但您似乎对 C++“讨厌”的东西有一些误解。这是非常广泛的,但它可能是进一步阅读的开始stackoverflow.com/questions/5854581/polymorphism-in-c
  • 在 Google 上快速搜索“C++ 多态性”应该会得到一些教程
  • 您可以通过创建存储类对象的动态对象来实现这一点。查看更多关于运行时多态性

标签: c++ class inheritance types information-retrieval


【解决方案1】:

你走在正确的轨道上,但你必须学习如何使用多态性。在您的示例中,您需要以下修复:

在基类中,将所有函数设为virtual,并添加virtual 析构函数:

class StorageInfo {
    public:
        virtual ~StorageInfo(){}
        virtual void initializeStorage();
        //...
 };

让你的继承公开

class StorageInfoA: public StorageInfo {

不要按值保存StorageInfo,而是将其保存在智能指针中:

class device {
    private:
        std::unique_ptr<StorageInfo> storage_info_;        
};

device 构造函数看起来像

//Somewhere in the constructor of device.cpp
if(save_to_cache){
    storage_info_ = std::make_unique<StorageInfoA>();
} else {
    storage_info_ = std::make_unique<StorageInfoB>();
}

最后,您将像使用普通指针一样使用它:

    storage_info_->updateStorageInfo();

【讨论】:

  • 非常感谢!代码库非常大,所以我仍在努力实现它,但从它的声音来看,这正是我想要的。
  • @MochaPower19 我注意到我在析构函数中遗漏了 virtual 这个词 - 现在已修复。
猜你喜欢
  • 1970-01-01
  • 2017-06-02
  • 1970-01-01
  • 2021-10-08
  • 2017-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-06
相关资源
最近更新 更多