Forward声明了typedef保护

时间:2018-05-23 12:26:45

标签: c++ c++11 forward-declaration

我试图转发声明在类中私有使用的一些变量,以限制使用此类时必须包含的标题数。

可悲的是,我要转发的类声明是一个typedef,它是我无法编辑的第三方库(让我们称之为“boost :: asio :: strand”)参数)

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

  • 只需包含标题并接受它是不可能的
  • 转发声明什么是typedef'ed并添加我自己的typedef

看第二个解决方案,有没有办法可以保护自己免受库中typedef更改的影响,以便编译器在删除/重命名类时使用typedef而不是使用未定义类型它减少了维护头痛?

1 个答案:

答案 0 :(得分:0)

如果可能的话,我会尽量不依赖原始课程的前瞻声明。我可能错过了一个案例,但我认为如果类型以某种方式出现在方法签名中,或者如果您的类包含以某种方式指向或引用该类型的成员(可能是间接的),则前向声明仅对纯粹的私人用途有用。 / p>

我建议转发声明类的包装器,并且只在实现文件中定义实际类或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;
};

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

我会像这样改变MyClass:

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