2011-02-04 6 views
2

나는 연결된 목록이 Foo입니다. Foo는 기본 클래스이며 여러 클래스가 상속합니다. 말해봐, 클래스 A, B, and C.상속받은 개체의 클래스를 알아보기

나는이 링크 된 목록을 순환하면서 3 개의 정의가있는 some_method 메서드를 호출합니다. 각 하위 클래스의 하나가 A, B 및 C 물체의 분류를 가지고대로 입력 Foo의 정도로

some_method(A a); 
some_method(B b); 
some_method(C c); 

연결 목록은 포괄적이다.

current_element에서 연결된 목록을 순환하면서 some_method(current_element);으로 전화를 걸 때 어떻게 올바른 방법으로 전화를 걸 수 있습니까? 컴파일러는 일반 Foo을 사용하는 some_method를 작성할 때까지 불평하고 그 메서드로만 호출합니다.

답변

3

요구 사항에 따라 다형성 사용을 고려할 수 있습니다. 이렇게하려면 기본 노드 클래스에 순수 가상 메서드를 추가하고 해당 메서드를 파생 클래스로 이동합니다. 이 작업을 위해

class Foo 
{ 
public: 
    virtual void some_method() = 0; 
}; 

class A : Foo 
{ 
public 
    virtual void some_method() 
    { 
    // move the body of some_method(A a) here 
    } 
}; 

, 연결된 목록 대신 Foo의, Foo*가 필요합니다.

http://en.wikipedia.org/wiki/Visitor_pattern

+0

Foo는 거의 소리가 나지 않습니다. some_method에 액세스 할 수 있으면 메서드에 매개 변수로 전달됩니다. Foo 포인터의 연결리스트가 데이터 멤버 – bandai

0

RTTI은 귀하의 친구입니다. 링크에 제공된 예제는 더 이상 당신을 안내 할 것입니다

+0

마지막 수단으로 RTTI 만 사용합니다. 마지막 수단은'Foo'를 절대 수정할 수없는 경우입니다. 예를 들어 링크가 아니라 upvote 것입니다. –

-1

회원 클래스에 대한 메소드를 멤버 메소드로 호출 할 수 있습니다. 예를 들어 A a = new A(); a.some_method()은 올바른 방법을 호출해야합니다. some_method() 내에서 this 키워드를 사용하여 object를 참조 할 수 있습니다.

+0

어쩌면 나는 오해하고 있지만 이것이 효과가있는 것처럼 보이지는 않습니다. 나는 내가 분명히해야한다고 생각한다. A는 연결된 목록이 저장된 위치의 데이터 멤버입니다. A 객체는 some_method에 액세스 할 수 없습니다. some_method가 A 객체를 매개 변수로 사용하여 호출되었습니다. – bandai

+0

아, 미안하지만, "각 하위 클래스에 대해 하나"라고 말한 것은 각 클래스에 some_method() 정의가 포함되어 있음을 의미한다고 생각하는 것 같습니다. –

1

두 가지 방법 :

당신이 푸/A/B/C에 some_method를 넣을 수없는 경우

class Node 
{ 
public: 
    Foo* foo; 
    Node* next; 
}; 

// ... 

Node* someNode = GetNode(); 
// Calls correct method - A::some_method, B::some_method, or C::some_method 
someNode->foo->some_method(); 

것은, 당신은 방문자 디자인 패턴을 조사 할 수 있습니다

1) 더 좋은 방법 :

someMethod가 기본 클래스 Foo의 가상 메소드가되도록 디자인을 바꾸고 파생 클래스에서 재정의하십시오. 로 :

class Foo { 
    public: 
     virtual void someMethod() = 0; 
}; 

class A { 
    public: 
     void someMethod() { /* implementation specific to A here */ }; 
}; 

class B { 
    public: 
     void someMethod() { /* implementation specific to B here */ }; 
}; 

class C { 
    public: 
     void someMethod() { /* implementation specific to C here */ }; 
}; 

그런 다음 Foo에 대한 포인터에있는 것으로 someMethod를 호출 자동으로 적절한 클래스의 메소드를 호출합니다. someMethodFoo 또는 그 파생물의 일부로 구현 될 수 없기 때문에 수행 할 수없는 경우 (예 : 현재 디자인에있는 클래스의 비공개 멤버에 액세스해야하는 경우),이 기능을 하위 문제로 분리하려고 시도 할 수 있습니다. 이 클래스의 가상 메서드에 넣을 수 A B C.

2) 방법 "나는 선택의 여지가없는"

사용 RTTI (런타임 형식 식별이)가 C에 포함되어 ++. 기본 클래스 Foo에 적어도 하나의 가상 메소드가 있어야합니다.#include <typeinfo>이 필요하고 포인터에 typeid()을 사용하면 type_info 개체가 반환되고 해당 name() 결과는 ABC이라는 클래스 이름과 비교할 수 있습니다. 이는 오버 헤드가 더 많고 OOP 디자인 원칙을 위반하기 때문에 아주 좋은 접근법은 아닙니다. 하지만 그게 유일한 옵션이라면 괜찮습니다.

2

이것은 "이중 발송"문제입니다. 방문자 패턴을 사용할 수 있습니다. 일반적으로 Visitor는 기본 클래스이므로 여러 디자인에서이 디자인을 다시 사용할 수 있습니다.

#include <iostream> 
class FooVisitor; 

class Foo 
{ 
public: 
    virtual void some_method() = 0; 
    virtual void visit(FooVisitor* v) = 0; 
}; 

class A; 
class B; 
class FooVisitor 
{ 
public: 
    virtual void visit(A* a){ std::cout << "A" << std::endl;} 
    virtual void visit(B* b){std::cout << "B" << std::endl;} 
}; 

class A : public Foo 
{ 
public: 
     virtual void some_method() 
    { 
     // move the body of some_method(A a) here 
    } 
    virtual void visit(FooVisitor* v) { v->visit(this);} 
}; 

class B : public Foo 
{ 
public: 
     virtual void some_method() 
    { 
     // move the body of some_method(A a) here 
    } 
    virtual void visit(FooVisitor* v) { v->visit(this);} 
}; 

int main() 
{ 
    FooVisitor fv; 
    Foo* f1 = new A; 
    f1->visit(&fv); 
    Foo* f2 = new B; 
    f2->visit(&fv); 
    getchar(); 
} 
+0

+1 인 클래스 내에 있습니다. 방문객은 좋은 패턴입니다. 거기에는 단점이 있습니다 (방문자는 파생 된 각 유형에 대해 새로운 메소드를 가져야하므로 새 파생 클래스를 생성 할 때마다 수정해야합니다). 그러나 전체적으로 이것은 이와 같은 문제에서 좋은 선택이 될 수 있습니다. 나는 당신의 샘플 코드를 좋아한다. 그러나이 문제는 단일 발송 인 것으로 보이기 때문에 방문자 패턴이 반드시 필요하지는 않습니다 (우리는 파생 방문자가 필요하지 않습니다). –

+0

감사합니다. NB 실제 코드에는 많은 'const'가 필요합니다. – Keith

관련 문제