朋友 类 需要包含或转发声明 c++?
Friend classes need to include or forward declare c++?
在尝试使用队列构建二叉树时,我一直在为错误而苦苦挣扎。问题是 classes 应该包含哪些文件以及如何从其他 classes 引用对象?我将文件放入 IDE 以试图查明问题所在,结果如下。目前我的问题是 Queue.h 文件中的 treePtr "does not name a type"。可以看到这个问题的演变here 这个问题和其他帖子不一样的地方在于两个class是朋友class。这就带来了循环依赖的问题。我已经尝试了各种包含文件和转发声明的组合,但一种组合会导致一种类型的问题,另一种会产生不同的错误。
这里是主要的class:
#include <cstdlib>
#include "Tree.cpp"
using namespace std;
int main() {
Tree tree;
tree.addTreeNode(5);
return 0;
}
这里是 Queue.h:
#ifndef QUEUE_H_
#define QUEUE_H_
class Tree; //Was instructed to put this here
class Queue {
friend class Tree;
private:
typedef struct node {
Tree::treePtr treeNode; //Here is the problem
node* next;
}* nodePtr;
nodePtr head;
nodePtr current;
public:
Queue();
virtual ~Queue();
void push(Tree::treePtr t); //Here is the problem
int pop();
void print();
};
#endif /* QUEUE_H_ */
这是Tree.h:
#ifndef TREE_H_
#define TREE_H_
#include "Queue.h" //Was instructed to put this here
class Tree {
friend class Queue;
private:
Queue q; //Edit: Most likely problem since Queue and Tree are friends
typedef struct tree {
int data;
tree* left;
tree* right;
}* treePtr;
treePtr root;
int numNodes;
public:
Tree();
virtual ~Tree();
void addTreeNode(int integer);
};
#endif /* TREE_H_ */
这是tree.cpp
#include <cstdlib>
#include <iostream>
#include "Tree.h"
using namespace std;
Tree::Tree() {
root = NULL;
numNodes = 0;
}
void Tree::addTreeNode(int integer) {
numNodes++;
treePtr t = new tree;
t->left = NULL;
t->right = NULL;
t->data = integer;
cout << "add root\n";
root = t;
q.push(t); //This is a problem
q.print();
}
Tree::~Tree() {
// TODO Auto-generated destructor stub
}
您必须分别编译 Tree.cpp
和(我想您有一个)Queue.cpp
,而不是在 main.cpp
.
中包含 Tree.cpp
前向声明适合 classes,即使你这样做是循环的。
将 #include "Tree.h"
放入您的 Queue.cpp
文件中,让编译器看到完整的声明。
在 main.cpp
中输入 #include " Tree.h"
.
获取最终的可执行文件 link 所有生成的目标文件 main.o(bj)
、Tree.o(bj)
和 Queue.o(bj)
.
请参阅 [Why should I not include cpp files and instead use a header?]。
正如我现在注意到的,您的实际问题是,您无法从前向声明的 class/struct 访问嵌套的 classes/structs,因为您需要从 [=22] 访问 treePtr
=](treePtr
应该更好地命名为 TreeNode
或类似的 BTW)。
在这种情况下,您不能将 treePtr
设为私有嵌套类型,它必须公开可见。
一种可行的方法是将 treePtr
放在 namespace internal_
中,这表明它不适合在 API.
之外使用
另一种可行的方法是使 Queue
成为模板 class,接受任何类型的 tree
或其他类型的节点。既然看不到任何用例,为什么 Queue
需要了解 tree
的内部规范(除了像复制 aso 这样的琐碎的东西。),其实没有必要使 Queue
一个 friend
class.
我最好的猜测是问题在于,由于 classes Queue 和 Tree 是朋友,并且 Tree 有一个 Queue 实例作为数据成员,因此在尝试包含时发生了一些冲突文件并转发声明。通过与 Queue 共享数据成员,Tree class 与 Queue class 共享了 Queue 对象的实例化,因此存在一些不明显的初始共享。 @πìντα ῥεῖ 建议将队列设为模板 class 以便它可以接受任何类型的对象,而不必与树耦合(这样做是为了让队列 class 知道如何处理treePtr 对象)。使队列成为模板 class 解决了这个问题,因为现在树 class 可以有一个队列的实例,而且我可以将 treePtr 类型的对象传递给队列,而队列对树 class 之前。
在尝试使用队列构建二叉树时,我一直在为错误而苦苦挣扎。问题是 classes 应该包含哪些文件以及如何从其他 classes 引用对象?我将文件放入 IDE 以试图查明问题所在,结果如下。目前我的问题是 Queue.h 文件中的 treePtr "does not name a type"。可以看到这个问题的演变here 这个问题和其他帖子不一样的地方在于两个class是朋友class。这就带来了循环依赖的问题。我已经尝试了各种包含文件和转发声明的组合,但一种组合会导致一种类型的问题,另一种会产生不同的错误。
这里是主要的class:
#include <cstdlib>
#include "Tree.cpp"
using namespace std;
int main() {
Tree tree;
tree.addTreeNode(5);
return 0;
}
这里是 Queue.h:
#ifndef QUEUE_H_
#define QUEUE_H_
class Tree; //Was instructed to put this here
class Queue {
friend class Tree;
private:
typedef struct node {
Tree::treePtr treeNode; //Here is the problem
node* next;
}* nodePtr;
nodePtr head;
nodePtr current;
public:
Queue();
virtual ~Queue();
void push(Tree::treePtr t); //Here is the problem
int pop();
void print();
};
#endif /* QUEUE_H_ */
这是Tree.h:
#ifndef TREE_H_
#define TREE_H_
#include "Queue.h" //Was instructed to put this here
class Tree {
friend class Queue;
private:
Queue q; //Edit: Most likely problem since Queue and Tree are friends
typedef struct tree {
int data;
tree* left;
tree* right;
}* treePtr;
treePtr root;
int numNodes;
public:
Tree();
virtual ~Tree();
void addTreeNode(int integer);
};
#endif /* TREE_H_ */
这是tree.cpp
#include <cstdlib>
#include <iostream>
#include "Tree.h"
using namespace std;
Tree::Tree() {
root = NULL;
numNodes = 0;
}
void Tree::addTreeNode(int integer) {
numNodes++;
treePtr t = new tree;
t->left = NULL;
t->right = NULL;
t->data = integer;
cout << "add root\n";
root = t;
q.push(t); //This is a problem
q.print();
}
Tree::~Tree() {
// TODO Auto-generated destructor stub
}
您必须分别编译 Tree.cpp
和(我想您有一个)Queue.cpp
,而不是在 main.cpp
.
Tree.cpp
前向声明适合 classes,即使你这样做是循环的。
将 #include "Tree.h"
放入您的 Queue.cpp
文件中,让编译器看到完整的声明。
在 main.cpp
中输入 #include " Tree.h"
.
获取最终的可执行文件 link 所有生成的目标文件 main.o(bj)
、Tree.o(bj)
和 Queue.o(bj)
.
请参阅 [Why should I not include cpp files and instead use a header?]。
正如我现在注意到的,您的实际问题是,您无法从前向声明的 class/struct 访问嵌套的 classes/structs,因为您需要从 [=22] 访问 treePtr
=](treePtr
应该更好地命名为 TreeNode
或类似的 BTW)。
在这种情况下,您不能将 treePtr
设为私有嵌套类型,它必须公开可见。
一种可行的方法是将 treePtr
放在 namespace internal_
中,这表明它不适合在 API.
另一种可行的方法是使 Queue
成为模板 class,接受任何类型的 tree
或其他类型的节点。既然看不到任何用例,为什么 Queue
需要了解 tree
的内部规范(除了像复制 aso 这样的琐碎的东西。),其实没有必要使 Queue
一个 friend
class.
我最好的猜测是问题在于,由于 classes Queue 和 Tree 是朋友,并且 Tree 有一个 Queue 实例作为数据成员,因此在尝试包含时发生了一些冲突文件并转发声明。通过与 Queue 共享数据成员,Tree class 与 Queue class 共享了 Queue 对象的实例化,因此存在一些不明显的初始共享。 @πìντα ῥεῖ 建议将队列设为模板 class 以便它可以接受任何类型的对象,而不必与树耦合(这样做是为了让队列 class 知道如何处理treePtr 对象)。使队列成为模板 class 解决了这个问题,因为现在树 class 可以有一个队列的实例,而且我可以将 treePtr 类型的对象传递给队列,而队列对树 class 之前。