我试图创建适当的头文件,其中不包含太多的其他文件以保持它们的干净并加快编译时间。转发基类的声明
我遇到的,而这样做的两个问题:
在基类向前声明不起作用。
class B; class A : public B { // ... }
对STD类的前向声明不起作用。
namespace std { class string; } class A { string aStringToTest; }
如何解决这些问题?
我试图创建适当的头文件,其中不包含太多的其他文件以保持它们的干净并加快编译时间。转发基类的声明
我遇到的,而这样做的两个问题:
在基类向前声明不起作用。
class B;
class A : public B
{
// ...
}
对STD类的前向声明不起作用。
namespace std
{
class string;
}
class A
{
string aStringToTest;
}
如何解决这些问题?
您无法解决的第一个问题。
第二个问题是没有什么关系的标准库类。这是因为你将类的实例声明为你自己类的成员。
这两个问题都是由于编译器必须能够从其定义中找出类的总大小。
但是,编译器可以计算出指向某个类的指针的大小,即使它尚未具有完整的定义。所以在这种情况下可能的解决方案是在消费类中有一个指针(或引用)成员。在基类案件
没有太大的帮助,因为你不会得到一个“是”的关系。
也不是值得做这样的事情std::string
。首先,它应该是一个字符缓冲区的方便包装,可以让你从简单的事情上进行内存管理。如果你持有一个指向它的指针,为了避免包含头部,你可能会考虑一个好主意。其次(正如在评论中指出的那样),std::string
是std::basic_string<char>
的类型定义。所以你需要转发declare(然后使用),相反,到那时候事情变得非常模糊和难以阅读,这是另一种成本。是不是真的值得吗?
在这两种情况下,编译器需要知道类型的大小。因此,前向声明是不够的。基类可以添加成员或需要虚拟表。字符串成员将需要增加类的大小来存储STL字符串类的大小。
正向声明STL类往往是不可取的,因为实现通常包括加快编制明确模板实例。
你太艰苦设法解决的东西,实际上不是一个问题。使用你需要的头文件,并减少 - 在哪里可能 - 对它们的要求。但是,不要试图把它带到极端,因为你会失败。
在某些情况下,PIMPL成语可能对您有所帮助,但不在此处。
对于你的基类,你需要有完整的类型定义,而不仅仅是一个声明。派生类型头文件需要#include它们的基类的头文件。
对于std名称空间中的类,你必须包括正确的头文件 - <字符串>在这种情况下 - 然后做3两件事:
完全限定的类型:的std :: string aStringToTest
将一个使用声明仅用于 类型:using std :: string;
为 std命名空间使用声明:using namespace std;
正如埃里克回答过,你不能在任何的情况下,因为编译器需要知道类的大小使用前声明。
只能在一组操作使用前向声明:
你不能用它来
(我也不曾忘记任何?)
考虑到,如果宣告auto_ptr
是不一样的声明原始指针,因为auto_ptr
研究所当超出范围并且删除需要完整声明类型时,antiation会尝试删除指针。如果您使用auto_ptr
来保存前向声明类型,则必须提供析构函数(即使为空),并在完整的类声明被发现后对其进行定义。
还有一些其他的微妙之处。当你转发声明一个类时,你告诉编译器它将是一个类。这意味着它不能成为另一种类型的enum
或typedef
。这就是你所得到的问题,当你尝试转发声明std::string
,因为它是一个模板的特定实例的类型定义:
typedef basic_string<char> string; // aproximate
要转发声明字符串,你就需要转发声明basic_string
模板,然后创建typedef
。问题在于标准没有说明模板需要的参数的数量,它只是表明如果它需要多个参数,其余的参数必须具有默认类型,以便上面的表达式编译。这意味着没有标准的方式来转发宣告模板。
如果你要转发申报非标准模板另一方面(非STL,这是)你可以,只要你知道的参数个数做到这一点:
template <typename T, typename U> class Test; // correct
//template <typename T> class Test; // incorrect even if U has a default type
template <typename T, typename U = int> class Test {
// ...
};
最后,罗迪给你的建议是:尽可能地向前宣布,但假设必须包括一些事情。
>似乎前向声明对于基类和stl类是没用的。
更正... 对于基类和对象成员,前向声明是INAPPROPRIATE。 (它不是“无用的”,它是“不适用的”。)
当声明基类为另一个类的基类时,必须声明基类(未向前声明)。
当由另一个类,参数或返回值声明对象成员时,必须声明(未向前声明)对象成员。注意:by-reference或by-pointer没有这个约束。
更正... STL类的前向声明 - 根据ISO 14882 - 未定义的行为。 http://www.gotw.ca/gotw/034.htm
事实上,即使他使用了字符串指针或引用,TomWij也会遇到问题。他犯了错误,认为std :: string是一个类,事实并非如此。它是模板basic_string <>的typedef,并且根本无法进行前向声明。 – 2008-12-23 21:26:46
@Shmoopty:准确地说,它不能被转发声明,因为模板参数的数量在标准中是未定义的。实现可以将其他模板参数添加到语言所需的参数。 – 2008-12-23 21:38:05