我正在尝试创建正确的头文件,其中不包含太多其他文件以保持其清洁并加快编译时间.
这样做时遇到两个问题:
基类的前向声明不起作用.
class B; class A : public B { // ... }
关于STD类的前向声明不起作用.
namespace std { class string; } class A { string aStringToTest; }
我该如何解决这些问题?
你无法解决的第一个问题.
第二个问题与标准库类无关.这是因为您将类的实例声明为您自己的类的成员.
这两个问题都是由于要求编译器必须能够从其定义中找出类的总大小.
但是,编译器可以计算出指向类的指针的大小,即使它还没有完整的定义.因此,在这种情况下,可能的解决方案是在消费类中使用指针(或引用)成员.
在基类案例中帮助不大,因为你不会得到'是'关系'.
也不值得这样做std::string
.首先,它应该是一个方便的字符缓冲区包装器,以避免对这么简单的事情进行内存管理.如果你拿着一个指向它的指针,只是为了避免包含标题,你可能会把一个好主意放得太远.
其次(正如评论中所指出的)std::string
是一个typedef std::basic_string
.因此,您需要转发声明(然后使用),而这时候事情变得非常模糊和难以阅读,这是另一种成本.是不是真的值得吗?
正如Earwicker之前所回答的那样,在任何情况下都不能使用前向声明,因为编译器需要知道类的大小.
您只能在一组操作中使用前向声明:
声明将前向声明的类作为参数或返回它的函数
声明成员指针或对前向声明的类的引用
在类定义中声明前向声明类型的静态变量
你不能用它
声明给定类型的成员属性(编译器需要大小)
定义或创建该类型的对象或删除它
调用类的任何静态或成员方法或访问任何成员或静态属性
(我忘了吗?)
请注意声明a auto_ptr
与声明原始指针不同,因为auto_ptr
实例化将在超出范围时尝试删除指针,并且删除需要完整声明类型.如果使用auto_ptr
in来保存前向声明的类型,则必须提供析构函数(即使为空)并在看到完整的类声明后定义它.
还有其他一些细微之处.当你转发声明一个类时,你告诉编译器它将是一个类.这意味着它不能是一种enum
或typedef
另一种类型.当您尝试转发声明时std::string
,这是您遇到的问题,因为它是模板的特定实例化的typedef:
typedef basic_stringstring; // aproximate
要转发声明字符串,您需要转发声明basic_string
模板然后创建typedef
.问题是标准没有说明basic_string
模板所采用的参数数量,它只是声明如果它需要多个参数,那么其余参数必须具有默认类型,以便上面的表达式编译.这意味着没有标准的方式来转发声明模板.
另一方面,如果你想要转发声明非标准模板(非STL,那就是),只要你知道参数的数量就可以这样做:
templateclass Test; // correct //template class Test; // incorrect even if U has a default type template class Test { // ... };
最后,Roddy给你的建议:尽可能多地向前宣布,但是假设必须包含一些东西.