31

如果我像这样创建一个类:

// B.h
#ifndef _B_H_
#define _B_H_

class B
{
private:
    int x;
    int y;
};

#endif // _B_H_

并像这样使用它:

// main.cpp
#include <iostream>
#include <vector>

class B; // Forward declaration.

class A
{
public:
    A() {
        std::cout << v.size() << std::endl;
    }

private:
    std::vector<B> v;
};

int main()
{
    A a;
}

编译时编译器失败main.cpp。现在我知道的解决方案是#include "B.h",但我很好奇它为什么会失败。g++orcl的错误信息在这件事上都不是很有启发性。

4

8 回答 8

32

实际上,如果 A 的构造函数在知道 B 类型的编译单元中实现,则您的示例将构建。

std::vector 实例具有固定大小,无论 T 是什么,因为它包含,正如其他人之前所说的,只包含一个指向 T 的指针。但是向量的构造函数取决于具体类型。您的示例无法编译,因为 A() 尝试调用向量的 ctor,而在不知道 B 的情况下无法生成该 ctor。以下是可行的方法:

A的声明:

// A.h
#include <vector>

class B; // Forward declaration.

class A
{
public:
    A(); // only declare, don't implement here

private:
    std::vector<B> v;
};

A的实现:

// A.cpp
#include "A.h"
#include "B.h"

A::A() // this implicitly calls vector<B>'s constructor
{
    std::cout << v.size() << std::endl;
}

现在 A 的用户只需要知道 A,而不需要 B:

// main.cpp
#include "A.h"

int main()
{
    A a; // compiles OK
}
于 2013-03-13T10:29:06.843 回答
31

编译器需要知道“B”有多大,才能生成适当的布局信息。相反,如果你说std::vector<B*>,那么编译器不需要知道 B 有多大,因为它知道指针有多大。

于 2008-09-01T01:29:43.617 回答
5

要实例化 A::v,编译器需要知道 B 的具体类型。

如果您试图最小化#included 包的数量以缩短编译时间,您可以做两件事,它们实际上是彼此的变体:

  1. 使用指向 B 的指针
  2. 使用轻量级代理到 B
于 2008-09-01T01:29:36.940 回答
3

需要的不仅仅是 B 的大小。例如,现代编译器将有一些花哨的技巧来在可能的情况下使用 memcpy 来加速向量复制。这通常是通过部分专注于元素类型的 POD 来实现的。您无法从前向声明中判断 B 是否是 POD。

于 2008-09-26T12:19:08.393 回答
3

就像 fyzix 所说,您的前向声明不起作用的原因是您的内联构造函数。即使是空的构造函数也可能包含大量代码,例如非 POD 成员的构造。在您的情况下,您有一个要初始化的向量,如果不完全定义其模板类型,您就无法做到这一点。

析构函数也是如此。向量需要模板类型定义来告诉在销毁它持有的实例时要调用什么析构函数。

要摆脱这个问题,不要内联构造函数和析构函数。在 B 完全定义后的某个地方单独定义它们。

如需更多信息, 请访问 http://www.chromium.org/developers/coding-style/cpp-dos-and-donts

于 2015-02-17T19:18:01.833 回答
1

无论您是使用向量还是尝试实例化一个 B,这都无关紧要。实例化需要对象的完整定义。

于 2008-09-26T12:53:35.223 回答
0

伙计,您正在std::vector使用不完整的类型进行实例化。不要碰前向声明,只需将构造函数的定义移动到.cpp文件中。

于 2012-12-23T12:19:41.570 回答
-12

您不能使用前向声明的原因是因为 B 的大小是未知的。

在您的示例中没有理由不能在 Ah 中包含 Bh,那么您真正想解决什么问题?

编辑:还有另一种方法可以解决这个问题:停止使用 C/C++!这是 1970 年代... ;)

于 2008-09-01T01:30:10.697 回答