名称空间中类的前向声明
Forward declaration of a class in a namespace
如何在命名空间中向前声明类。例如,下面是一个库的头文件,用户不需要知道私有的myPtr,所以当包含在头文件下面时不需要包含boost头文件。那么,我如何向前声明boost::shared_ptr来启用用户代码编译呢?
MyClass.h
class MyClass
{
private:
boost::shared_ptr<Mytype> myPtr;
}
TL;DR这里需要包含<boost/shared_ptr.hpp>
。没有(聪明的)变通办法。但是MyType
本身可以前向声明。
当然,你可以在标题的顶部写#include <boost/shared_ptr.hpp>
,这样你的用户就不必自己做了。实际上,提供自治的标头(即可以首先包含而不会出现错误的标头)是一种很好的做法。
关于前向编译的规则稍微复杂一些。比起试图记住所有的案例,理解它们的原因更容易。
有两个因素:
- <
- 语义/gh>内存属性(size &对齐)
语义:为了访问对象的方法、属性或基类,你需要了解它们。当然,除了构造函数、赋值操作符和析构函数,即使是自动生成的,也是方法之外,这似乎是显而易见的。我们很容易忘记它们。
内存属性:与大多数语言不同,c++试图尽可能高效,这意味着它会为对象直接分配内存,而不是在某处分配内存并在使用点使用指针,除非你指示它这样做(通过使用指针或引用)。为了知道要分配多少,编译器需要看到对象的内部,即在底层是什么。这意味着,即使确切的细节是不可访问的(private
/protected
的东西),他们需要是可见的,所以它可以看到,24个字节对齐在一个8字节的边界是必需的(不相关的shared_ptr
顺便说一下)。
好了,现在我们知道了原因,我们可以检查各种东西。当:
时需要定义:- 使用对象作为
sizeof
或alignof
的参数?yes(显然,需要内存属性) - 使用对象作为属性?yes(需要内存属性)
- 使用对象作为静态属性?没有 (1)
- 使用指针或引用对象作为属性?没有 (2)
- 在函数声明中使用对象作为参数?没有 (3)
- 在函数声明中使用对象作为返回类型?没有 (3)
- 传递指针或引用到一个对象周围?没有 (4)
- 转换为基类?yes(语义检查存在&基类可访问性)
- 转换为另一种类型? 取决于(5)
(1)声明不需要任何东西,但是静态属性的定义需要对象的定义。
(2)指针是32位或64位大(取决于你如何编译,…)独立于对象。引用具有实现定义的表示。
(3)即使按值接受/返回!但是,函数定义(如果在内部使用)或函数调用站点可能需要它。
(4)当然,如果你尝试使用它(p->foo()
或p.foo()
),那就是另一回事了。
(5)如果需要使用对象的转换操作符,那么显然是必需的;否则,如果使用其他类型的构造函数,则适用与函数相同的规则(但需要使用其他类型定义)。
我希望事情现在更清楚了。
- 在命名空间 c++ 中正确声明 extern 变量
- 在命名空间中声明变量,在 main 中定义它,使其对所有其他文件可见
- 转发声明在命名空间中不起作用的替代方法
- 在C++中,如果成员引用在其声明中初始化,为什么需要存储空间?
- C++ 17 个友元函数声明和内联命名空间
- 为什么 gcc 无法从其前向声明中检测到友元类命名空间?
- 声明"使用命名空间 C;"对于证明 [namespace.udir]/3 中的示例中显示的结果至关重
- 命名空间内C++变量声明
- 在命名空间中声明变量
- C++ 没有在命名空间外部声明的类主体的类
- 如何在命名空间中声明外部全局,然后定义它?
- 在 c++ 中在运行时声明对命名空间的引用
- 警告定义朋友操作员在名称空间内声明
- 声明是否有可能逃脱其封闭的名称空间
- 有没有办法转发声明命名空间或只是提前使其可见
- 声明方法时没有名称空间,也没有对C 作用的方法的对象
- C 无法解释的类“尚未声明”错误,这是由于名称空间而导致的
- 如何在不同的命名空间中使用双重声明的 extern "C"函数进行 clang 构建(如 msvc 和 gcc)
- 在同一命名空间中声明变量和函数是否出错?[C++]
- c++等价于for calloc和为数组变量声明空间