繁体   English   中英

在此设计中,我可以使用dynamic_cast以外的其他功能吗?

[英]Can I use something other than dynamic_cast in this design?

在我们的系统中,

  • 多种设备类型
  • 每个deviceType可以具有不同的配置类型
  • 每个deviceType将是其自己的库

我处于不得不使用dynamic_cast的情况。 我想知道是否有更好的方法来设计它?

我所拥有的是:

// in common code
class Config {public: virtual ~Config(){} }; 

    class Device {
     protected:
        Config* devConfig;
    protected:
        virtual void createDevConfig() = 0;
    public:
        virtual void display() = 0;
    };

    // Device specific Code
    class A0Device : public Device {
    protected:
        virtual void createDevConfig() { this->devConfig = new A0Config(); }
    public:
        A0Device() { this->createDevConfig(); }

        virtual void display(){
        A0Config* config = dynamic_cast<A0Config*>(this->devConfig);

        if(!config) std::cout << "Null object\n";

        }
    };

    class A0Config : public Config {};

    int main() {
        Device* dev = new A0Device();
        dev->display();
        return 0;
    }

本质上, A0Device具有自己的配置类型: A0Config ,由其他成员组成。 A0Device在基类devConfig定义为Config* A0Device::display() -我需要访问devConfig对象(作为A0Config类型)。 virtual createDevConfig()确保config对象在A0Device始终为A0Config类型=>在此处使用dynamic_cast是否安全? 有没有更好的设计方法?

如果您可以支持额外的(在通用系统中为最小,在实时/嵌入式系统中为最小)运行时开销,则可以安全地使用dynamic_cast<>

但是,您必须意识到这个“小”细节。 给出的表达式dynamic_cast<T*>(expr) ,每当动态类型的*expr 既不 T或子类T表达evalutates为空指针, nullptr 而且,当然, 取消引用nullptr调用未定义的行为,并且将在大多数平台上导致崩溃

但是, 仅当您知道您的代码在这种情况下会崩溃时,检查nullptr可能不值得。

因为C ++是一碗盛有汤和冰淇淋,土豆和咖啡的碗,而且当然,每个想法都来自Stroustrup / C ++受托人的耳朵/头脑,所以有几种选择:

  • 向下转换 static_cast<T*>(expr) ,尽管这与将某些内容转换为不是的东西具有相同的问题。
  • 对于发现“必需的” C语言的人,在此不需要reinterpret_cast<T*>(expr) ,但它在那里。
  • 如果您认为某种东西可以正常工作,并且知道该对象在运行时可能在一个地方的所有类型,则可以对带有union for holding the data enum for the type使用enum for the type union for holding the data带有placement new union for holding the dataexplicit destructor calls supercombo。
  • 如果问题涉及数据,则可以在Base中使用诸如virtual Config &getConfig() = 0之类的东西,以及诸如ABC123Config config; Config &getConfig { return this->config; }类的东西ABC123Config config; Config &getConfig { return this->config; } ABC123Config config; Config &getConfig { return this->config; } ABC123Config config; Config &getConfig { return this->config; }
  • 仅适用于像我这样的疯子 :使用C风格/构造函数风格的演员表。

希望这可以帮助!

您可以在基础中有一个纯虚函数,该虚函数返回Config指针或引用(除非需要指针,否则我希望使用该指针),然后将其存储在派生类中。 这个问题/答案涵盖了指针和引用之间的区别: 何时使用引用与指针

这种设计的优势在于,基础中任何需要Config东西都可以使用getConfig ,而任何需要使用派生类的东西都可以不进行强制转换。 另外,您无需调用newdelete

class Device {
   protected:
      virtual Config& getConfig() = 0;
   ...
};

class A0Device {
public:
   ...
   Config& getConfig() {return config;}
   ...
private:
   A0Config config;
};

[不确定,如果我在这里缺少什么,但是听起来或多或少听起来像是设计的气味]

为什么A0Config无法聚合Config

通常,点击dynamic_cast可以暗示在建立IS-A关系方面有些dynamic_cast 在这种情况下, A0Config提供了一些不适合其基类Config功能( getA() ),也许它违反了LSP-Liskov替换原理,从而违反了强的IS-A

但是, 如果可以用一种以上的方式表达阶级关系,请使用最实用的最弱关系– Herb Sutter

...而肖恩·帕特恩(Sean Parent)达到了这种程度。 继承是邪恶的基础

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM