Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/109.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 声明的循环依赖关系_C++_Design Patterns - Fatal编程技术网

C++ 声明的循环依赖关系

C++ 声明的循环依赖关系,c++,design-patterns,C++,Design Patterns,我试图实现visitor模式的示例,但在类声明的循环依赖性方面遇到了问题。当我做类访问者的转发声明时,类Russia和England不知道访问者有方法visit,但当我扩展方法accept的访问者转发声明时,我需要使用类England和Russia,但他们需要知道访问者是谁,因为他们在代码中使用了这种类型。我尝试了许多不同的代码排序方法,但完全失败了。请帮助我理解,C++需要什么。谢谢 #include <cstdio> #include <vector> using

我试图实现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;isize();i++){ l->at(i).接受(v); } } }; int main(){ 英国; 俄罗斯,; 向量出行计划; 旅行计划。推回(英国); 行程计划。推回(俄罗斯); 旅行计划。推回(英国); 行程我的行程(&行程计划); 拜访我; 我的旅行。接受(和我); 返回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’ C++ ANSI-墙- WTU-WTW-WORD -迂回-WNO未使用参数-O VP VP.CC vp.cc:在成员函数“virtual void England::accept(const Visitor*)”中: vp.cc:40:错误:无效使用不完整的类型“const struct Visitor” vp.cc:30:错误:“const struct Visitor”的转发声明 vp.cc:在成员函数“virtual void Russia::accept(const Visitor*)”中: vp.cc:47:错误:无效使用不完整的类型“const struct Visitor” vp.cc:30:错误:“const struct Visitor”的转发声明
<>我很久没有写复杂的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解决了这个问题,但出现了新问题:我不想“解决”这个问题。我想知道什么是错的,为什么。但是谢谢。这个问题已经从原来的问题中分离出来了: