【问题标题】:Forward declare a typedef protection前向声明 typedef 保护
【发布时间】:2018-11-02 10:40:43
【问题描述】:

我正在尝试转发声明一些仅在类中私下使用的变量,以限制我在使用该类时必须包含的标头数量。

遗憾的是,我要转发声明的类原来是 typedef,它是我无法编辑的第 3 方库(为了方便起见,我们将其称为“boost::asio::strand”论据)

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

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

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

【问题讨论】:

  • 使用粉刺?͏͏͏͏͏͏͏͏
  • @wally 虽然它确实有效并且肯定消除了包含对象的需要,但这不是我想要做的,因为这意味着与其拥有(例如)私人std::vector<typedefedThing*>我现在需要一个pimpl*,其中包含std::vector<typedefedThing*>。C&C++ 的概念是你不用为你不用的东西付费,而且我不需要这个额外的对象的成本。跨度>
  • 第三方库是否在命名空间内?
  • @PasserBy 是的。为了争论,我们可以称这个命名空间为“boost”。
  • 您知道,在尝试回答之后,我认为这里没有足够的信息。为什么只需要前向声明?你打算在你的公共界面中使用它吗?在这种情况下,您的用户仍将包含标题。你只私下使用吗?那你为什么只能使用前向声明呢?

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


【解决方案1】:

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

我建议为类转发声明一个包装器,并且只在实际类或 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();
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-06-19
    • 1970-01-01
    • 1970-01-01
    • 2010-10-22
    • 1970-01-01
    • 2013-06-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多