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