1

我如何转发在命名空间中声明一个类。例如下面是一个库的头文件,用户不需要知道私有 myPtr 所以在包含下面的头文件时不需要包含 boost 头文件。那么如何转发声明 boost::shared_ptr 以启用用户代码编译?

我的类.h

class MyClass
{

private:

  boost::shared_ptr<Mytype> myPtr;

}
4

1 回答 1

2

TL;DR<boost/shared_ptr.hpp>此处需要包含。没有(智能)方式解决它。MyType本身可以前向声明。

当然,您可以只写#include <boost/shared_ptr.hpp>在标题的顶部,这样您的用户就不必自己做。提供自治标头(即可以首先包含而没有错误的标头)实际上是一种很好的做法。


前向编译的规则稍微复杂一些。理解它们的原因比尝试记住所有案例更容易。

有两个因素:

  • 语义
  • 内存属性(大小和对齐)

语义:为了访问对象的方法、属性或基类,您需要了解它们。当然,看起来很明显,除了构造函数、赋值运算符和析构函数,即使是自动生成的,也是方法。很容易忘记它们。

内存属性:与大多数语言不同,C++ 尝试尽可能高效,这意味着它将在此处为对象分配内存,不是在某处分配内存,并且只在使用点使用指针,除非您指示它这样做当然是这样(通过使用指针引用)。为了知道要分配多少,编译器需要查看对象的内部结构,即引擎盖下的内容这意味着即使无法访问确切的详细信息(private/ protectedstuff),它们也需要可见,因此可以看到需要在 8 字节边界上对齐的 24 字节(shared_ptr顺便说一下不相关)。

在标准中,我们说对象的定义对于这两种需求(方法和内存布局)中的任何一种都是必需的。如果需要定义,那么它必须是显而易见的。


好的,既然我们知道了原因,我们就可以检查各种事情了。在以下情况下是否需要定义:

  • 使用对象作为sizeoforalignof的参数 (显然,需要内存属性)
  • 使用对象作为属性?(需要内存属性)
  • 使用对象作为静态属性?没有(1)
  • 使用指向对象的指针或引用作为属性?没有(2)
  • 在函数声明中使用对象作为参数?没有(3)
  • 在函数声明中使用对象作为返回类型?没有(3)
  • 传递指向对象的指针或引用?没有(4)
  • 铸造到基类?(对基类的存在和可访问性进行语义检查)
  • 转换为另一种类型?取决于(5)

(1) 声明不需要任何东西,但是静态属性的定义将需要对象的定义。

(2) 指针是 32 位或 64 位大(取决于您如何编译,...),与对象无关。引用具有实现定义的表示。

(3) 即使按值取/返回!函数定义(如果在其中使用)或函数调用站点可能需要它。

(4) 当然,如果您尝试使用它 (p->foo()p.foo()) 那就另当别论了。

(5) 如果需要使用对象的转换运算符,那么显然是必须的;否则,如果您使用其他类型的构造函数,则适用与函数相同的规则(尽管需要其他类型定义)。

我希望现在情况更清楚了。

于 2013-01-12T18:25:02.130 回答