C++ 在B类中使用A类向量

C++ 在B类中使用A类向量,c++,class,vector,C++,Class,Vector,我创建了一个类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_ */

我创建了一个类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_ */
#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_ */
//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 */ }
};
\ifndef A\u H_
#定义一个_
#包括“B.h”
#包括
使用名称空间std;
甲级{
公众:
vector bvector;//下面是错误
A();
};
#endif/*A_H_*/
B类标题:

#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_ */
#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_ */
//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 */ }
};
#ifndef B#H_
#定义B_H_
#包括“A.h”
#包括
使用名称空间std;
B类{
vector aVector;//这里是错误
公众:
B();
};
#endif/*B_H_*/
但我得到以下错误:

“。\src/B.h:16:8:错误:“A”未在此范围内声明

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

..\src/B.h:16:9:错误:模板参数2无效“


如果我删除了B中的坏行,它会转到
A.h
。我做错了什么?

这里的诀窍是你需要向前声明两个类中的一个。不幸的是,转发声明不允许您在头中使用完整类型-它们只允许您使用指向该类型的指针。所以即使这样在这种情况下也不起作用

您可以使用PIMPL惯用语(指向实现的指针)(google that)来规避这个问题

PIMPL习惯用法基本上要求您创建第三种类型。然后,类型B将包含一个指向包含类型a的向量的实现类的指针。应该在B中保存的向量的所有操作都将转发到实际保存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_ */
#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_ */
//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 */ }
};
//正向声明impl类。
BImpl类;
B类{
私人:
BImpl*impl;
公众:
void PrintVector(){impl->PrintVector();}
};
甲级{
私人:
std::vec;
公众:
void PrintVector(){/*Do printing*/}
};
类BImpl{
私人:
std::vec;
公众:
void PrintVector(){/*Do Printing*/}
};

我还没有包括这些类的构造函数或填充方法,但您应该了解一般的想法:)

您有一个循环依赖关系

A.h
包括
B.h
,其中包括
A.h
,但是
A\u h
防护已定义,因此跳过
A.h
的内容,从而处理
B.h
的内容,它指的是
A
,但是它还没有定义,因为除了
\define
\include
指令在
A.h

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

您正在创建一个类之间的连接。这通常是一件坏事,尤其是在C++中。 为了编译A,编译器需要知道B的定义(#包括“B.h”)。不幸的是,B头包含对类的引用(这里是循环引用)。 编译器无法处理这种情况,因为当前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_ */
#ifndef B#H_
#定义B_H_
#包括
使用名称空间std;
甲级//A类远期申报
B类{
vector aVector;//请注意,现在只能使用指向
公众:
B();
};
#endif/*B_H_*/
使用转发声明基本上告诉编译器类型a将在其他地方定义。编译器可以依赖这一事实,但它对A一无所知(特别是它忽略了A的大小及其方法)。
因此,在B内部,如果您正向声明了A,则只能使用指向A类的指针(指针的大小始终相同),并且不能从B内部调用A类的任何方法。

您必须对其中一个进行正向声明(但由于您可以同时对两个进行正向声明,因此您应该同时对两个进行正向声明,而不应包含任何一个标头).@SethCarnegie Forward声明仅适用于指针:@num3ric它适用于任何不完整类型足够的地方,包括
vector
的声明@SethCarnegie,您是对的,它适用于任何不完整类型足够的地方,但
std::vector
需要完整类型。用不完整的类型实例化大多数标准库模板是未定义的行为,请参见[res.on.functions]/2@JonathanWakely如果我理解正确的话,解决方案是一个旁路,因此我做了C++中的错误,所以编译器(预处理器?)在A中开始,包含本身没有包含语句的B。然后它处理BImpl,包括A,但A已经被定义,所以什么也不会发生。问题解决了。对吗?@user1778406-你没有做错什么。在某些情况下,循环引用是生活中的事实。它们有时可能表明您应该重新考虑您的设计-它可能过于复杂。如果你能设计出来,很好,否则,这是一个很好的解决方案。实际上,这最初是一个解决方案,用于将实现与声明解耦,以简化编译单元之间的依赖关系,但它也适用于这种情况。@num3ric-差不多。B可以使用BImpl,因为它只使用前向声明的指针。A可以使用B,因为B是先定义的。BImpl可以使用,因为A是在BImpl之前定义的。你可以把它分成多个文件,它会工作的很好-为了便于演示,我只是在一个地方做了所有的事情。非常感谢,这对我帮助很大。