C++ 声明的循环依赖关系
我试图实现visitor模式的示例,但在类声明的循环依赖性方面遇到了问题。当我做类访问者的转发声明时,类Russia和England不知道访问者有方法visit,但当我扩展方法accept的访问者转发声明时,我需要使用类England和Russia,但他们需要知道访问者是谁,因为他们在代码中使用了这种类型。我尝试了许多不同的代码排序方法,但完全失败了。请帮助我理解,C++需要什么。谢谢 #include <cstdio> #include <vector> using namespace std; class Visitor; class Land { public: virtual void accept(const Visitor *v); }; class England : public Land { public: void accept(const Visitor *v) { v->visit(this); } }; class Russia : public Land { public: void accept(const Visitor *v) { v->visit(this); } }; class Visitor { public: void visit(const England *e) const { printf("Hey, it's England!\n"); } void visit(const Russia *r) const { printf("Hey, it's Russia!\n"); } }; class Trip { private: vector<Land> *l; public: explicit Trip(vector<Land> *_l):l(_l) {} void accept(Visitor *v) { for (unsigned i = 0; i < l->size(); i++) { l->at(i).accept(v); } } }; int main() { England england; Russia russia; vector<Land> trip_plan; trip_plan.push_back(england); trip_plan.push_back(russia); trip_plan.push_back(england); Trip my_trip(&trip_plan); Visitor me; my_trip.accept(&me); return 0; } #包括 #包括 使用名称空间std; 班级访客; 阶级土地{ 公众: 虚拟无效接受(const Visitor*v); }; 英格兰类:公共土地{ 公众: 无效接受(常量访客*v){ v->参观(本次); } }; 俄罗斯类:公共土地{ 公众: 无效接受(常量访客*v){ v->参观(本次); } }; 班级访客{ 公众: 无效访问(康斯特英格兰*东)康斯特{ printf(“嘿,是英格兰!\n”); } 无效访问(const俄罗斯*r)const{ printf(“嘿,是俄罗斯!\n”); } }; 集体旅行{ 私人: 向量*l; 公众: 显式Trip(向量*_l):l(_l){} 无效接受(访客*v){ 对于(无符号i=0;iC++ 声明的循环依赖关系,c++,design-patterns,C++,Design Patterns,我试图实现visitor模式的示例,但在类声明的循环依赖性方面遇到了问题。当我做类访问者的转发声明时,类Russia和England不知道访问者有方法visit,但当我扩展方法accept的访问者转发声明时,我需要使用类England和Russia,但他们需要知道访问者是谁,因为他们在代码中使用了这种类型。我尝试了许多不同的代码排序方法,但完全失败了。请帮助我理解,C++需要什么。谢谢 #include <cstdio> #include <vector> using
<>我很久没有写复杂的C++程序了,但是如果我记得正确的话,你应该把这些类的骨架用<这个代码> >代码>文件中的同一个名字来命名为<代码> .h >代码>文件。然后将其包含在此
.c
文件中
希望这有帮助。在使用前给出所有类类型声明。。我想这会有用的。亚历克西已经给出了部分答案
class Visitor;
class England : public Land {
public:
void accept(const Visitor *v); // Only declaration
};
// Define Visitor
class Visitor {
//...
};
// Now implementation
void England::accept(const Visitor *v) {
v->visit(this);
}
但是,如果您不打算实施土地验收,则需要:
class Land {
public:
virtual void accept(const Visitor *v)= NULL;
};
Alexey Malistov的回答确实解决了你的问题。
这也暴露了下一个问题
gcc编译器正在抱怨vtable(用于具有虚拟函数的类,以及其他内容)。其使用的规则已记录在案(请参阅):
如果该类声明了任何非内联、非纯虚函数,则第一个函数将被选择为该类的“键方法”,并且vtable仅在定义键方法的转换单元中发出
现在,Alexey版本的类定义了非内联、非纯虚拟函数accept。因此,gcc推迟了Land vtable的实例化,直到它看到Land::accept的定义。加上这个,看看它是否有效。或者,正如尼古拉兹所说,让它成为一个纯粹的虚拟世界
嗯,我不想“解决”这个问题。我想知道什么是错的,为什么
习惯于将声明与定义分开。除了模板的特殊情况,C++的工作方式也会更好。< P>当你转发声明时,C++编译器知道有一个用户定义的类型,但是它不知道它的数据成员和方法。为了使用此用户定义类型的全部功能,您需要在使用它们之前包含它的头文件,其中包含所有它的方法和数据成员,否则您只需进行转发声明,并在包含头文件的地方使用它的方法和数据成员。 在您的例子中,您正在调用前向声明的Visitor类的visit()方法,这样您就可以通知编译器有一个Visitor数据类型,但编译器还不知道visit()方法。为了解决这个问题,您必须删除转发声明,并将访问者定义放在所有类的顶部。你会有这样的东西
#include <cstdio>
#include <vector>
using namespace std;
class England;
class Russia;
class Visitor {
public:
void visit(const England *e) const {
printf("Hey, it's England!\n");
}
void visit(const Russia *r) const {
printf("Hey, it's Russia!\n");
}
};
class Land {
public:
virtual void accept(const Visitor *v);
};
class England : public Land {
public:
void accept(const Visitor *v) {
v->visit(this);
}
};
class Russia : public Land {
public:
void accept(const Visitor *v) {
v->visit(this);
}
};
...
#包括
#包括
使用名称空间std;
英国阶级;
俄罗斯阶级;
班级访客{
公众:
无效访问(康斯特英格兰*东)康斯特{
printf(“嘿,是英格兰!\n”);
}
无效访问(const俄罗斯*r)const{
printf(“嘿,是俄罗斯!\n”);
}
};
阶级土地{
公众:
虚拟无效接受(const Visitor*v);
};
英格兰类:公共土地{
公众:
无效接受(常量访客*v){
v->参观(本次);
}
};
俄罗斯类:公共土地{
公众:
无效接受(常量访客*v){
v->参观(本次);
}
};
...
恐怕这不能解决问题。现在我得到了很多-,未定义的引用到vtable for Land',以及未定义的引用到typeinfo for Land'。你真的在任何地方定义了类Land吗?我想你可能想让土地变成纯虚拟的:类土地{public:virtual~Land(){}virtual void accept(constvisitor*v)=0;};您看到的错误是GCC没有为Land创建vtable,因为您从未为它定义过任何函数。Alexey解决了这个问题,但出现了新问题:我不想“解决”这个问题。我想知道什么是错的,为什么。但是谢谢。这个问题已经从原来的问题中分离出来了: