【问题标题】:Automate pimpl'ing of C++ classes -- is there an easy way?自动化 C++ 类的 pimpl'ing - 有没有简单的方法?
【发布时间】:2010-12-09 22:29:42
【问题描述】:

Pimpl 是许多 C++ 代码中样板的来源。它们似乎是宏、模板和一些外部工具帮助的组合可以解决的问题,但我不确定最简单的方法是什么。 I've seen templates 有助于做一些提升但并不多——您最终仍需要为您尝试包装的类的每个方法编写转发函数。有没有更简单的方法?

我在想像制作过程中使用的工具。您希望您的公共标头是 pimpl'd 类,因此您提供一些输入文件,例如 pimpl.in,其中列出了您想要包装的类(实现 un-pimpl'd),然后检查该文件,生成 pimpl 类,并且在“make install”期间仅安装它们的头文件(不是原始类的头文件)。问题是如果没有完整的 C++ 解析器,我看不到任何方法可以做到这一点,即使是编译器供应商也无法做到这一点。也许这些类可以以某种方式编写,使外部工具的工作更容易,但我确信我最终会错过各种极端情况(例如模板化类和/或模板化成员函数)。

有什么想法吗?有没有其他人已经为这个问题提供了解决方案?

【问题讨论】:

  • Lazy C++ 做了类似的事情。

标签: c++ templates build-process macros pimpl-idiom


【解决方案1】:

一种选择是改用接口类:

class ClassA {
  virtual void foo() = 0;
  static ClassA *create();
};

// in ClassA.cpp

class ImplA : public ClassA {
/* ... */
};
ClassA *ClassA::create() {
  return new ImplA();
}

然而,这确实增加了获取 vtable 函数指针的开销。

除此之外,我想不出任何这样的工具。正如您所说,解析 C++ 并非易事,并且还有其他语言不那么成问题(例如,C# 或 Java 后期绑定所有内容,因此您可以稍后更改它们的内存布局而不会出现问题)。

【讨论】:

    【解决方案2】:

    不,没有一个简单的答案。 :-( 我认为几乎每个 OO 专家都说“更喜欢组合而不是继承”,会有语言支持让组合比继承容易得多。

    【讨论】:

      【解决方案3】:

      我并不是说这很好(只是突然想到的东西)。
      但是您可以尝试重载运算符 ->

      #include <memory>
      #include <iostream>
      
      class X
      {
          public:
          void plop()
          {
              std::cout << "Plop\n";
          }
      };
      
      class PimplX
      {
          public:
              PimplX()
              {
                  pimpl.reset(new X);
              }
              X* operator->()
              {
                  return pimpl.get();
              }
          private:
              PimplX(PimplX const&);
              PimplX& operator=(PimplX const&);
              std::auto_ptr<X>    pimpl;
      };   
      
      
      int main()
      {    
          PimplX      x;
      
          x->plop();
      }
      

      【讨论】:

      • 这是一个有趣的想法,虽然你最终还是会直接在 X 对象上调用函数,这意味着你需要公开 X 的标头和定义,所以 X 不会完全不透明。另一方面,如果您主要针对 ABI 进行 pimpling 而不是使类不透明(并且可以相信用户不会直接选择使用 X,而是在其标头可用时直接使用 X),我认为没关系。
      • 此外,在 C++ 中的类定义中定义的函数是隐式内联的。您需要将 PimplX 的构造函数和 operator-> 定义移出类,以免将调用者绑定到 X 的 ABI。
      猜你喜欢
      • 1970-01-01
      • 2011-04-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-21
      • 1970-01-01
      • 1970-01-01
      • 2010-09-06
      相关资源
      最近更新 更多