2009-11-17 5 views
5

방문자 패턴의 예를 구현하려고하지만 클래스 선언의 순환 종속성에 문제가 있습니다. 클래스 방문자의 선언을 할 때, 러시아와 영국의 클래스는 메소드 방문을 가지고있는 것을 모릅니다 만, 메소드의 수락을 위해 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’ 

답변

8
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); 
} 
+0

문제가 해결되지 않을까 걱정됩니다. 이제'vtable for Land '에 대한 정의되지 않은 참조와'typeinfo for Land'에 대한 정의되지 않은 참조가 많이 있습니다. – Martin

+0

실제로 Land 클래스를 정의 했습니까? 아마 토지를 가상으로 만들고 싶다고 생각합니다. 클래스 Land { public : virtual ~ Land() {} virtual void accept (const Visitor * v) = 0; }; GCC가 아무 기능도 정의하지 않았기 때문에 GCC가 Land 용 vtable을 만들지 않았다는 오류가 있습니다. –

+0

글쎄, Alexey이 문제를 해결했지만 새로운 문제가 발생합니다 : http://stackoverflow.com/questions/1748827/virtual-tables-are-undefined – Martin

0

나는 오랫동안 복잡한 C++ 프로그램을 작성하지 않은하지만 난 제대로 기억한다면, 당신은 때와 .h 파일에 해당 클래스의 골격을해야 이 .c 파일과 동일한 이름입니다. 그런 다음이 파일을이 .c에 포함 시키십시오.

희망이 도움이됩니다.

+0

음, 문제를 "해결"하고 싶지는 않습니다. 나는 무엇이 잘못되었고, 왜 그런지 이해하고 싶다. 하지만 고마워. – Martin

0

사용하기 전에 모든 클래스 유형 선언을주세요. 제대로 작동한다고 생각합니다.

1

알렉시는 이미 대답의 한 부분을주었습니다. 당신이 토지에 대한 동의를 구현하기 위하여려고하지 않는 경우

그러나, 당신이 필요합니다

class Land { 
    public: 
    virtual void accept(const Visitor *v)= NULL; 
}; 
+0

이 문제는 원래의 질문에서 분리되었습니다 : http://stackoverflow.com/questions/1748827/virtual-tables-are-undefined – Martin

1

알렉세이 Malistov의 대답 이 문제를 해결 않습니다. 다음 문제도 드러납니다.

gcc 컴파일러는 vtable (다른 것들 중에서 가상 함수가있는 클래스에 사용됨)에 대해 불평하고 있습니다. 이 문서화되어 사용 규칙 (docs 참조)

을 클래스가 아닌 인라인이 아닌 순수 가상 함수를 선언하는 경우, 첫 번째는 클래스의 "키 방법"및 VTABLE로 선택 키 메서드가 정의 된 번역 단위에서만 생성됩니다.

지금, 당신의 클래스의 알렉세이의 버전은 인라인이 아닌, 비 순수 가상 함수 을 받아 정의합니다. 그래서 gcc는 토지 vtable의 인스턴스 화를 Land :: accept의 정의를 볼 때까지 연기합니다. 그것을 추가하고 그것이 효과가 있는지보십시오. Nicholaz가 말했듯이, 순수 가상으로 만 만들 수 있습니다.

음, 문제를 "해결"하고 싶지 않습니다. 내가 잘못 이해하고 싶은 이유

은 정의의 선언을 오토넷에 익숙해. 템플릿의 특수한 경우를 제외하면 C++은 이런 식으로 더 잘 작동하는 경향이 있습니다.

1

선언을 전달할 때 C++ 컴파일러는 사용자 정의 유형이 있음을 알고 있지만 데이터 멤버 및 메소드에 대해 알지 못합니다.이 사용자 정의 유형의 전체 기능을 사용하려면 헤더 파일을 포함해야합니다. 사용하기 전에 모든 메소드 및 데이터 멤버가 위치해야합니다. 그렇지 않으면 앞으로 선언을 만들고 헤더 파일이있는 메소드 및 데이터 멤버를 사용합니다. 포함. Forward 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); 
    } 
}; 
... 
+0

감사합니다. – Martin

관련 문제