此问题在此处已有答案:
Resolve build errors due to circular dependency amongst classes(12个答案)
11天前关闭
我试图实现访问者模式的例子,但是我在类声明的循环依赖方面遇到了麻烦。当我做Visitor类的前向声明时,类Russia和England不知道Visitor有方法visit,但是当我扩展Visitor的前向声明为方法accept时,我需要使用类England和Russia,但是它们需要知道Visitor是谁,因为他们在他们的代码中使用这种类型。我尝试了许多排序代码的变化,但我完全失败了。请帮助我理解,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;
}
字符串
这是g++输出
c++ -ansi -Wall -Wextra -Wconversion -pedantic -Wno-unused-parameter -o vp vp.cc
vp.cc: In member function ‘virtual void England::accept(const Visitor*)’:
vp.cc:40: error: invalid use of incomplete type ‘const struct Visitor’
vp.cc:30: error: forward declaration of ‘const struct Visitor’
vp.cc: In member function ‘virtual void Russia::accept(const Visitor*)’:
vp.cc:47: error: invalid use of incomplete type ‘const struct Visitor’
vp.cc:30: error: forward declaration of ‘const struct Visitor’
型
6条答案
按热度按时间u91tlkcl1#
字符串
wfauudbj2#
亚历克斯已经给出了答案的一部分。
但是,如果你不打算实现土地接受,那么你需要:
字符串
anhgbhbe3#
阿列克谢·马利斯托夫的回答确实解决了你的问题,但它也暴露了下一个问题。
gcc编译器正在抱怨vtable(它用于带有虚函数的类,以及其他东西)。它使用的规则有文档记录(参见文档):
如果类声明了任何非内联、非纯虚函数,则第一个虚函数将被选为类的“键方法”,并且vtable仅在定义键方法的翻译单元中发出。
现在,Alexey的类版本定义了非内联、非纯虚函数 accept。因此,gcc推迟了 Land vtable的示例化,直到它看到 Land::accept 的定义。添加它,看看它是否有效。或者,正如Nicholaz所说,只是使它成为纯虚函数。
我不想“解决”问题,我想知道什么是错的,为什么
习惯于将声明与定义分开。除了模板的特殊情况,C++倾向于以这种方式工作得更好。
gzszwxb44#
当你转发声明时,C++编译器知道有这种类型的用户定义类型,但它不知道它的数据成员和方法。为了使用这种用户定义类型的全部功能,您需要在使用它们之前包含它的头文件,其中包含所有它的方法和数据成员,否则您只需进行正向声明,并使用它的方法和数据成员。包含头文件。在你的例子中,你调用了forward声明的Visitor类的visit()方法,这样你就通知了编译器有一个Visitor数据类型,但是编译器还不知道visit()方法。为了解决这个问题,你必须删除forward声明,把Visitor定义放在所有类的顶部。你会得到这样的东西
字符串
92vpleto5#
我已经很久没有写过复杂的C++程序了,但是如果我没记错的话,你应该把
.h
文件中的那些类的 backbone 和这个.c
文件同名,然后把它包含到这个.c
文件中。希望这对你有帮助。
p3rjfoxz6#
给予所有类类型声明之前,它的使用..我认为这将工作。