4

我创建了一个 A 类和一个 B 类,我试图在 A 中设置一个 B 类型的向量,在 B 中设置一个 A 类型的向量:

A类标题:

#ifndef A_H_
#define A_H_

#include "B.h"
#include <vector>
using namespace std;
class A {

public:
    vector<B> bvector; // here is the error
    A();
};

#endif /* A_H_ */

B类标题:

#ifndef B_H_
#define B_H_
#include "A.h"
#include <vector>

using namespace std;

class B {
vector<A> aVector; //Here is the error

public:
    B();
};

#endif /* B_H_ */

但我收到以下错误:

“..\src/Bh:16:8: 错误: 'A' 未在此范围内声明

..\src/Bh:16:9:错误:模板参数 1 无效

..\src/Bh:16:9:错误:模板参数 2 无效”

如果我删除 B 中的坏行,则翻转到哪个A.h。我做错了什么?

4

3 回答 3

2

我创建了一个 A 类和一个 B 类,我试图在 A 中设置一个 B 类型的向量,在 B 中设置一个 A 类型的向量

您正在创建类之间的循环依赖关系。这通常是一件坏事,尤其是在 C++ 中。

编译器为了编译 A,需要知道 B 的定义(#include "Bh")。不幸的是,B 标头包含对 A 类的引用(这里是循环引用)。编译器无法处理这种情况,因为 A 标头已包含在当前 TU 中(请参阅包含防护)。

尽管经常有循环引用是糟糕设计的征兆,但您最终可以使用前向声明来克服这个问题。例如,您可以这样修改 B:

#ifndef B_H_
#define B_H_

#include <vector>

using namespace std;
class A; //forward declaration of class A
class B {
vector<A*> aVector; //note that you must only use pointer to A now 

public:
    B();
};

#endif /* B_H_ */

Using a forward declaration basically tells the compiler that a type A will be defined somewhere else. The compiler can rely on this fact, but it does not know anything about A (particularly it ignores the size of A and its methods). So inside B, if you have forward declared A, you can use only pointers to A classes (pointers have always the same size) and you can't call any methods of an A class from inside B.

于 2012-11-04T22:24:14.780 回答
1

这里的诀窍是您需要转发声明两个类之一。不幸的是,前向声明不允许您在标头中使用完整类型——它们只允许您使用指向该类型的指针。因此,即使在这种情况下也行不通。

你可以使用PIMPL idiom (Pointer to IMPlementation) (google that) 来规避这个问题。

PIMPL 成语基本上会让您创建第三种类型。然后你的 B 类型将持有一个指向包含 A 类型向量的实现类的指针。应该在 B 中保存的向量的所有操作都将转发到实际保存 A 向量的新实现类。

例如:

//Forward declare impl class.
class BImpl;

class B {
    private:
        BImpl* impl;

    public:
        void PrintVector() { impl->PrintVector(); }
};

class A {
    private:
        std::vector<B> vec;

    public:
        void PrintVector() { /* Do printing */ }
};

class BImpl {
    private:
        std::vector<A> vec;

    public:
        void PrintVector() { /* Do Printing */ }
};

我没有包含这些类的构造函数或填充方法,但是您应该了解总体思路:)

于 2012-11-04T22:20:59.363 回答
0

你有一个循环依赖。

A.h包括B.hwhich contains A.h,但是A_H_已经定义了守卫,因此A.h跳过了 的内容,因此B.h处理AA.h#define#includeA.h

于 2012-11-04T22:22:56.577 回答