代码之家  ›  专栏  ›  技术社区  ›  UKMonkey

向前声明typedef保护

  •  5
  • UKMonkey  · 技术社区  · 7 年前

    我试图转发声明一些只在类中单独使用的变量,以限制使用此变量时必须包含的头的数量。

    遗憾的是,我要转发声明的类原来是一个typedef,它是一个我无法编辑的第三方库(为了参数起见,我们称它为“boost::asio::strand”)

    这个问题 Forward declaration of a typedef in C++ 证明唯一的解决方案是:

    • 只需包含标题并接受这是不可能的
    • 向前声明将被类型定义的内容并添加我自己的typedef

    看看第二种解决方案,有没有什么方法可以保护自己不受库中typedef更改的影响,这样编译器在删除/重命名类时会抱怨typedef,而不是使用未定义的类型,从而减少维护方面的麻烦?

    1 回复  |  直到 7 年前
        1
  •  0
  •   PaulR    7 年前

    如果可能的话,我会尽量不依赖原始类的forward声明。我可能漏掉了一个case,但我认为只有当类型以某种方式出现在方法签名中时,或者如果您的类包含一个以某种方式指向或引用该类型的成员(可能是间接的),那么forward声明才有用。

    我建议向前声明类的包装器,并且只在知道实际类或typedef时在实现文件中定义它。

    // need header because it contains UglyTypeDef:
    #include <UglyHeader.h>
    
    class MyClass {
    public:
      int theMethod(int a);
    private:
      void uglyMethod(UglyTypeDef &utd);
    
      int someMember;
      UglyTypeDef *utdp;
      std::vector<UglyTypeDef *> utds;
    };
    

    在这个例子中,我们可以使用forward声明,但是我们不想依赖UglyHeader的内部。

    我会这样改变我的班级:

    class MyClass {
    public:
      int theMethod(int a);
    private:
      // move the private method into the implementation file   
    
      // hide the ugly typedef
      // we safely forward declare our own private wrapper
      struct UglyTypeDefWrapper;
    
      int someMember;
      UglyTypeDefWrapper *utdp;
      std::vector<UglyTypeDefWrapper *> utds;
    };
    

    现在,为了实现这一点,cpp文件中的实现也必须更改:

    #include "MyClass.hpp"
    #include <UglyHeader.h>
    
    struct MyClass::UglyTypeDefWrapper {
       // if possible save another level of indirection 
       // and store by value, otherwise use a second indirection
       // by cleverly wrapping at the right level of abstraction 
       // this abstraction can be free in many cases
       UglyTypeDef td;
    };
    
    namespace {
      // we completely hide the private method in this file as
      // an implementation detail and pass it whatever it needs
      // this also helps the compiler to inline it, 
      // because it knows it cannot be referenced in 
      // a different compilation unit
      // we need to pass all members as needed
      void uglyFormerMethod(int &someMember, UglyTypeDef &utd) {
        someMember += utd.whatever();
      }
    }
    
    int MyClass::theMethod(int a) {
      utd->td.doWhatever();
      uglyFormerMethod(someMember, *utd);
      for(auto utdwp: utds) {
        utdwp->td.doIt();
      }
    }