c++ 声明的循环依赖性[重复]

jvlzgdj9  于 2024-01-09  发布在  其他
关注(0)|答案(6)|浏览(190)

此问题在此处已有答案

Resolve build errors due to circular dependency amongst classes(12个答案)
11天前关闭
我试图实现访问者模式的例子,但是我在类声明的循环依赖方面遇到了麻烦。当我做Visitor类的前向声明时,类Russia和England不知道Visitor有方法visit,但是当我扩展Visitor的前向声明为方法accept时,我需要使用类England和Russia,但是它们需要知道Visitor是谁,因为他们在他们的代码中使用这种类型。我尝试了许多排序代码的变化,但我完全失败了。请帮助我理解,C++需要什么来获得这个。谢谢。

  1. #include <cstdio>
  2. #include <vector>
  3. using namespace std;
  4. class Visitor;
  5. class Land {
  6. public:
  7. virtual void accept(const Visitor *v);
  8. };
  9. class England : public Land {
  10. public:
  11. void accept(const Visitor *v) {
  12. v->visit(this);
  13. }
  14. };
  15. class Russia : public Land {
  16. public:
  17. void accept(const Visitor *v) {
  18. v->visit(this);
  19. }
  20. };
  21. class Visitor {
  22. public:
  23. void visit(const England *e) const {
  24. printf("Hey, it's England!\n");
  25. }
  26. void visit(const Russia *r) const {
  27. printf("Hey, it's Russia!\n");
  28. }
  29. };
  30. class Trip {
  31. private:
  32. vector<Land> *l;
  33. public:
  34. explicit Trip(vector<Land> *_l):l(_l) {}
  35. void accept(Visitor *v) {
  36. for (unsigned i = 0; i < l->size(); i++) {
  37. l->at(i).accept(v);
  38. }
  39. }
  40. };
  41. int main() {
  42. England england;
  43. Russia russia;
  44. vector<Land> trip_plan;
  45. trip_plan.push_back(england);
  46. trip_plan.push_back(russia);
  47. trip_plan.push_back(england);
  48. Trip my_trip(&trip_plan);
  49. Visitor me;
  50. my_trip.accept(&me);
  51. return 0;
  52. }

字符串
这是g++输出

  1. c++ -ansi -Wall -Wextra -Wconversion -pedantic -Wno-unused-parameter -o vp vp.cc
  2. vp.cc: In member function virtual void England::accept(const Visitor*)’:
  3. vp.cc:40: error: invalid use of incomplete type const struct Visitor
  4. vp.cc:30: error: forward declaration of const struct Visitor
  5. vp.cc: In member function virtual void Russia::accept(const Visitor*)’:
  6. vp.cc:47: error: invalid use of incomplete type const struct Visitor
  7. vp.cc:30: error: forward declaration of const struct Visitor

u91tlkcl

u91tlkcl1#

  1. class Visitor;
  2. class England : public Land {
  3. public:
  4. void accept(const Visitor *v); // Only declaration
  5. };
  6. // Define Visitor
  7. class Visitor {
  8. //...
  9. };
  10. // Now implementation
  11. void England::accept(const Visitor *v) {
  12. v->visit(this);
  13. }

字符串

展开查看全部
wfauudbj

wfauudbj2#

亚历克斯已经给出了答案的一部分。
但是,如果你不打算实现土地接受,那么你需要:

  1. class Land {
  2. public:
  3. virtual void accept(const Visitor *v)= NULL;
  4. };

字符串

anhgbhbe

anhgbhbe3#

阿列克谢·马利斯托夫的回答确实解决了你的问题,但它也暴露了下一个问题。
gcc编译器正在抱怨vtable(它用于带有虚函数的类,以及其他东西)。它使用的规则有文档记录(参见文档):
如果类声明了任何非内联、非纯虚函数,则第一个虚函数将被选为类的“键方法”,并且vtable仅在定义键方法的翻译单元中发出。
现在,Alexey的类版本定义了非内联、非纯虚函数 accept。因此,gcc推迟了 Land vtable的示例化,直到它看到 Land::accept 的定义。添加它,看看它是否有效。或者,正如Nicholaz所说,只是使它成为纯虚函数。
我不想“解决”问题,我想知道什么是错的,为什么
习惯于将声明与定义分开。除了模板的特殊情况,C++倾向于以这种方式工作得更好。

gzszwxb4

gzszwxb44#

当你转发声明时,C++编译器知道有这种类型的用户定义类型,但它不知道它的数据成员和方法。为了使用这种用户定义类型的全部功能,您需要在使用它们之前包含它的头文件,其中包含所有它的方法和数据成员,否则您只需进行正向声明,并使用它的方法和数据成员。包含头文件。在你的例子中,你调用了forward声明的Visitor类的visit()方法,这样你就通知了编译器有一个Visitor数据类型,但是编译器还不知道visit()方法。为了解决这个问题,你必须删除forward声明,把Visitor定义放在所有类的顶部。你会得到这样的东西

  1. #include <cstdio>
  2. #include <vector>
  3. using namespace std;
  4. class England;
  5. class Russia;
  6. class Visitor {
  7. public:
  8. void visit(const England *e) const {
  9. printf("Hey, it's England!\n");
  10. }
  11. void visit(const Russia *r) const {
  12. printf("Hey, it's Russia!\n");
  13. }
  14. };
  15. class Land {
  16. public:
  17. virtual void accept(const Visitor *v);
  18. };
  19. class England : public Land {
  20. public:
  21. void accept(const Visitor *v) {
  22. v->visit(this);
  23. }
  24. };
  25. class Russia : public Land {
  26. public:
  27. void accept(const Visitor *v) {
  28. v->visit(this);
  29. }
  30. };
  31. ...

字符串

展开查看全部
92vpleto

92vpleto5#

我已经很久没有写过复杂的C++程序了,但是如果我没记错的话,你应该把.h文件中的那些类的 backbone 和这个.c文件同名,然后把它包含到这个.c文件中。
希望这对你有帮助。

p3rjfoxz

p3rjfoxz6#

给予所有类类型声明之前,它的使用..我认为这将工作。

相关问题