C++ 基类的前向声明
我试图创建适当的头文件,其中不包括太多的其他文件,以保持它们干净,并加快编译时间 在执行此操作时,我遇到了两个问题:C++ 基类的前向声明,c++,class,forward-declaration,C++,Class,Forward Declaration,我试图创建适当的头文件,其中不包括太多的其他文件,以保持它们干净,并加快编译时间 在执行此操作时,我遇到了两个问题: 基类上的转发声明不起作用 class B; class A : public B { // ... } namespace std { class string; } class A { string aStringToTest; } STD类的转发声明不起作用 class B; class A : public B { // ..
class B;
class A : public B
{
// ...
}
namespace std
{
class string;
}
class A
{
string aStringToTest;
}
class B;
class A : public B
{
// ...
}
namespace std
{
class string;
}
class A
{
string aStringToTest;
}
如何解决这些问题?在这两种情况下,编译器都需要知道类型的大小。因此,预先声明是不够的。基类可以添加成员或需要虚拟表。字符串成员将要求增加类的大小以存储STL字符串类的大小
前向声明STL类通常是不可取的,因为实现通常包括显式模板实例化,从而加快编译速度。第一个问题是无法解决的 第二个问题与标准库类无关。这是因为您将类的实例声明为自己类的成员 这两个问题都是因为编译器必须能够从类的定义中找出类的总大小 然而,编译器可以计算出指向类的指针的大小,即使它还没有类的完整定义。因此,在这种情况下,一个可能的解决方案是在消费类中有一个指针(或引用)成员 在基类的情况下没有太多帮助,因为你不会得到一个“是一个”关系 像
std::string
这样的东西也不值得这么做。首先,它应该是一个方便的字符缓冲区包装器,以避免您在如此简单的事情上进行内存管理。如果你拿着一个指向它的指针,只是为了避免包含标题,那么你可能把一个好主意做得太过分了
其次(正如在评论中指出的),
std::string
是std::basic_string
的类型定义。因此,您需要向前声明(然后使用)相反,到那时事情变得非常模糊和难以阅读,这是另一种成本。这真的值得吗?你太努力了,想解决一些实际上不是问题的问题。使用您需要的头文件,并尽可能减少对它们的要求。但不要试图走极端,因为你会失败的
在某些情况下,PIMPL习惯用法可能会对您有所帮助,但在这里没有帮助。对于基类,您需要完整的类型定义,而不仅仅是声明。派生类型头需要#包含其基类的头 对于std名称空间中的类,必须包含正确的头(在本例中),然后执行以下三项操作之一:
正如Earwicker之前所回答的,在任何情况下都不能使用前向声明,因为编译器需要知道类的大小 只能在一组操作中使用转发声明:
- 声明将前向声明的类作为参数或返回它的函数
- 声明前向声明类的成员指针或引用
- 在类定义中声明前向声明类型的静态变量
- 声明给定类型的成员属性(编译器要求大小)
- 定义或创建该类型的对象,或将其删除
- 调用类的任何静态或成员方法,或访问任何成员或静态属性
auto_ptr
与声明原始指针不同,因为auto_ptr
实例化将在指针超出范围时尝试删除指针,删除需要完整的类型声明。如果在中使用auto_ptr
保存前向声明的类型,则必须提供析构函数(即使为空),并在看到完整的类声明后定义它
还有其他一些微妙之处。当您向前声明一个类时,您告诉编译器它将是一个类。这意味着它不能是另一类型的枚举
或类型定义
。这就是您在尝试转发declarestd::string
时遇到的问题,因为它是模板特定实例化的typedef:
typedef basic_string<char> string; // aproximate
最后,Roddy给您的建议是:尽可能多地向前声明,但假设必须包含一些内容。>似乎向前声明对于基类和stl类是无用的 更正。。。 转发声明不适用于基类和对象成员。(这不是“无用”,而是“不适用”。) 当基类被声明为另一个类的基类时,必须声明(而不是前向声明) 当对象成员被另一个类、参数或返回值声明时,必须声明(而不是向前声明)。注意:按引用或按指针不具有该约束 更正。。。 根据ISO 14882,STL类的正向声明是未定义的行为。
实际上,即使TomWij使用了字符串指针或引用,他也会遇到问题。他错误地假设std::string是一个类,而它不是。它是template basic_字符串的typedef,完全不能向前声明。@Shmoopty:准确地说,它不能向前声明,因为标准中未定义模板参数的数量。实现可以将其他模板参数添加到语言所需的模板参数中。即使您能够正确地获得这些参数,也可以在命名空间std中声明(除了从标准头中专门化模板之外)