我可以在此设计中使用除dynamic_cast之外的其他内容吗?

时间:2015-08-26 01:49:22

标签: c++ oop design-patterns casting dynamic-cast

在我们的系统中,我们有

  • 多个设备类型
  • 每个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()确保配置对象在A0Config =&gt;中始终为A0Device类型在这里使用dynamic_cast是否安全?有没有更好的设计方法?

3 个答案:

答案 0 :(得分:2)

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

但是,您必须了解这个“小”细节。给定dynamic_cast<T*>(expr)表达式,只要*expr的动态类型既不是 T,也不是T的子类,,表达式会重新评估为空指针nullptr 。当然,解除引用nullptr会调用未定义的行为,并会导致大多数平台崩溃

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

因为C ++是一个包含汤和冰淇淋,土豆和咖啡的碗,当然,每个想法都来自Stroustrup / C ++委员会的耳朵/思想,有几种选择:

  • 向下转换 static_cast<T*>(expr),虽然这与将某些东西投射到其他东西上的问题相同但不是。
  • 对于那些认为“必要”的C人来说,reinterpret_cast<T*>(expr)在此不是必需的,但它就在那里。
  • 如果你两者认为某些东西在工程上是完美的,如果它有效,并且你知道所有对象在运行时可能在一个地方拥有的类型,那么你可以使用enum for the type union for holding the dataplacement new explicit destructor callsvirtual Config &getConfig() = 0 supercombo。
  • 如果问题中涉及数据内容,您可以在Base中使用ABC123Config config; Config &getConfig { return this->config; },并在Derived中使用foldr (\c (x:xs) -> if c == '/' then "":x:xs else (c:x):xs ) [""] "hello/my/friends"
  • 对于像我这样的狂热爱好者 :使用C风格/构造函数式演员。

希望这有帮助!

答案 1 :(得分:1)

你可以在基础中有一个纯虚函数,它返回一个Config指针或引用(除非你需要一个指针,我更喜欢它),然后在派生类中存储。这个问题/答案涵盖了指针和参考文献之间的差异:When to use references vs. pointers

这种设计的优点是基础中需要Config的任何东西都可以使用getConfig,而任何需要使用派生类的东西都可以不进行强制转换。此外,您无需致电newdelete

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

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

答案 2 :(得分:0)

[不确定,如果我在这里遗漏了一些东西,但它或多或少听起来像是一种设计气味]

为什么A0Config无法汇总Config

通常,点击dynamic_cast是一个线索,表明在建立 IS-A 关系方面有些不对劲。在这种情况下,A0Config提供了一些不适合其基类getA()的功能(Config),可能违反了LSP-Liskov Substitution Principle,从而违反了强大的IS- A

尽管如此,If a class relationship can be expressed in more than one way, use the weakest relationship that's practical – Herb Sutter

...而Sean Parent就是这样。 Inheritance is the base class of evil