我如何转发在命名空间中声明一个类。例如,下面是一个库的头文件,用户不需要知道私有myPtr,因此当包含在头文件下面时不需要包含boost头。那么如何转发声明boost :: shared_ptr以启用用户代码编译?
MyClass.h
class MyClass
{
private:
boost::shared_ptr<Mytype> myPtr;
}
答案 0 :(得分:2)
TL; DR 此处需要包含<boost/shared_ptr.hpp>
。没有(聪明的)方式。 MyType
本身可以向前宣布。
当然,您只需在标题顶部写上#include <boost/shared_ptr.hpp>
,这样您的用户就无需自行完成。实际上,提供自治标头(即可以首先包含且没有错误的标头)是一种很好的做法。
关于正向编译的规则稍微复杂一些。理解它们的原因比试图记住所有案例更容易。
有两个因素:
语义:为了访问对象的方法,属性或基类,您需要了解它们。当然,似乎很明显,除了构造函数,赋值运算符和析构函数,即使是自动生成的,也是方法。很容易忘记它们。
内存属性:与大多数语言不同,C ++尝试尽可能高效,这意味着它将为对象分配内存而不是在某处分配并且只是在使用点使用指针,除非你指示它当然这样做(通过使用指针或引用)。为了知道要分配多少,编译器需要查看对象的 guts ,即底层的内容。这意味着即使无法访问确切的详细信息(private
/ protected
东西),它们也需要可见,因此可以看到需要在8字节边界上对齐24个字节(与{无关) {顺便说一下} {。}}。
在标准中,我们说对象的定义是这两种需求(方法和内存布局)中的任何一种都需要的。如果需要定义,那么它必须明显可用。
好的,既然我们知道原因,我们可以检查各种事情。是否需要定义:
shared_ptr
或sizeof
的参数? 是(显然,需要内存属性)(1)声明不需要任何内容,但静态属性的定义将需要对象的定义。
(2)指针是32位或64位大(取决于你如何编译,...),与对象无关。引用具有实现定义的表示。
(3)即使按值获取/返回!可能需要函数定义(如果在其中使用)或函数调用站点。
(4)当然,如果您尝试使用它(alignof
或p->foo()
),那么这是另一个故事。
(5)如果你需要使用对象的转换运算符,那么它显然是必需的;否则,如果您使用其他类型的构造函数,则应用与函数相同的规则(尽管需要其他类型定义)。
我希望现在事情更清楚了。