Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/164.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 基类的前向声明_C++_Class_Forward Declaration - Fatal编程技术网

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;
    }
    
  • STD类的转发声明不起作用

    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名称空间中的类,必须包含正确的头(在本例中),然后执行以下三项操作之一:

  • 完全限定类型:std::string 阿斯汀托斯特酒店

  • 将使用声明放在 类型:使用std::string

  • 为项目输入一个使用声明 std名称空间:使用名称空间std


  • 正如Earwicker之前所回答的,在任何情况下都不能使用前向声明,因为编译器需要知道类的大小

    只能在一组操作中使用转发声明:

    • 声明将前向声明的类作为参数或返回它的函数
    • 声明前向声明类的成员指针或引用
    • 在类定义中声明前向声明类型的静态变量
    你不能用它来

    • 声明给定类型的成员属性(编译器要求大小)
    • 定义或创建该类型的对象,或将其删除
    • 调用类的任何静态或成员方法,或访问任何成员或静态属性
    (我忘了吗?)

    考虑到声明
    auto_ptr
    与声明原始指针不同,因为
    auto_ptr
    实例化将在指针超出范围时尝试删除指针,删除需要完整的类型声明。如果在中使用
    auto_ptr
    保存前向声明的类型,则必须提供析构函数(即使为空),并在看到完整的类声明后定义它

    还有其他一些微妙之处。当您向前声明一个类时,您告诉编译器它将是一个类。这意味着它不能是另一类型的
    枚举
    类型定义
    。这就是您在尝试转发declare
    std::string
    时遇到的问题,因为它是模板特定实例化的typedef:

    typedef basic_string<char> string; // aproximate
    

    最后,Roddy给您的建议是:尽可能多地向前声明,但假设必须包含一些内容。

    >似乎向前声明对于基类和stl类是无用的

    更正。。。 转发声明不适用于基类和对象成员。(这不是“无用”,而是“不适用”。)

    当基类被声明为另一个类的基类时,必须声明(而不是前向声明)

    当对象成员被另一个类、参数或返回值声明时,必须声明(而不是向前声明)。注意:按引用或按指针不具有该约束

    更正。。。 根据ISO 14882,STL类的正向声明是未定义的行为。

    实际上,即使TomWij使用了字符串指针或引用,他也会遇到问题。他错误地假设std::string是一个类,而它不是。它是template basic_字符串的typedef,完全不能向前声明。@Shmoopty:准确地说,它不能向前声明,因为标准中未定义模板参数的数量。实现可以将其他模板参数添加到语言所需的模板参数中。即使您能够正确地获得这些参数,也可以在命名空间std中声明(除了从标准头中专门化模板之外)