声明但不定义内部结构/类 - 是否合法的C++代码?

8
以下代码是否合法的C++代码?
class Foo
{
  class Bar;

  void HaveADrink(Bar &bar);
  void PayForDrinks(Bar &bar);

  public:
  void VisitABar(int drinks);
};

class Foo::Bar
{
  public:
  int countDrinks;
};

void Foo::HaveADrink(Bar &bar)
{
  bar.countDrinks++;
}
void Foo::PayForDrinks(Bar &bar)
{
  bar.countDrinks = 0;
}
void Foo::VisitABar(int drinks)
{
  Bar bar;
  for (int i=0; i<drinks; i++) HaveADrink(bar);
  PayForDrinks(bar);
}

Visual C++ 和 GCC 都可以接受这个代码,但是对我来说,这个代码看起来有些奇怪,我不想在将来的编译器中被拒绝。

然而,这种模式对我来说似乎很有用,可以减少编译时的依赖性。我经常使用它来声明结构体,这些结构体用于传递一些“上下文”(一堆变量),这些变量被多个函数共享,这些函数都驻留在同一个 cpp 文件中,这样我就不必将“上下文”定义引入公共接口。


我正在制作一些上下文类,所以我也很感兴趣。顺便说一句,将countDrinks设置为公共可访问的。 - stefaanv
我猜你指的是 class Foo::Bar 的定义,对吗? - MSalters
2个回答

10

隐藏实现细节对于外部世界来说是合法的,而且确实有用。


9

[编辑] 我最初称之为“pimpl惯用法”:http://c2.com/cgi/wiki?PimplIdiom 但我同意这只是pimpl的一部分。这种技术被pimpl所使用。

你正在类Foo内部“转发”类Bar。只要在定义Foo时不执行任何需要sizeof Bar的操作即可合法。您可以使用指针或引用(Bar *或Bar&)引用Bar,但如果在Foo中声明数据成员,例如:

private: Bar _bar;

它将无法工作。原因是Foo的定义必须足以确定Foo的大小。由于在Foo的定义内部未知Bar的大小,这将使Foo的大小不确定。但使用指针会起作用:

private: Bar* _bar;

因为指针的sizeof相同,因此无论如何定义Bar,都是已知的。


2
嗯,这不完全是pimpl惯用语(他的代码中没有pimpl),但你是对的 - 本质上就是。+1 - sbi
1
这仅涉及pimpl,因为它更多关注一些上下文的范围,而pimpl是您类的完整实现。但你是正确的:只有在这样做时才能声明指针。请自行使用适当的智能指针以避免问题。 - stefaanv
这绝对不是PIMPL。Bar中没有实现。 - Martin York
它通常与Pimpl结合使用,声明一个“Impl”类用于实现,但它具有更广泛的应用范围(例如提到的上下文)。 - Matthieu M.
1
虽然这可能不是典型的pimpl实现,但在我看来它本质上是相同的。与普通的pimpl惯用语不同的唯一区别是Bar没有用于在不同的公共方法调用之间维护状态。但是,如果该类不需要在该时间段内维护该状态,则没有理由保留它,因此没有理由在堆上动态分配它。 - Michael Burr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接