2012-10-13 3 views
2

이것은이 플랫폼에서의 첫 번째 질문입니다. 어떤 것이 불분명하거나 적절한 방법으로 질문하지 않은 경우 유감입니다.기본 클래스에서 파생 된 템플릿 클래스가 동일한 지 확인하십시오.

아래 코드는 C++ 11 컴파일러에서 컴파일해야합니다. 나는 그것을 최소한으로 줄이려고 노력했다. 이 코드의 의미는이 절차를 수행하는 동안 잃었다 수도 있지만 아직도 내가 같은 매개 변수를 모두 호출 할 멤버 함수 클래스 목록을 유지하려고 노력 및 해당하고 명확해야한다 :

#include <iostream> 

class Base { 
public: 
    virtual void Call(int x) = 0; 
}; 

template<class T> class Extended : public Base 
{ 
    public: 
    // Constructor. 
    Extended(T* ptr, void (T::*memberFunction)(int)) : _ptr(ptr), _memberFunction(memberFunction) { } 

    // Call function. 
    void Call(int x) { 
    (_ptr->*_memberFunction)(x); 
    } 

private: 
    // Pointer to class T. 
    T* _ptr; 

    // Function pointer. 
    void (T::*_memberFunction)(int); 

}; 

class Test1 { 
public: 
    void Fun1(int x) { std::cout << "Hello " << x << std::endl; } 
}; 

class Test2 { 
public: 
    void FunX(int x) { std::cout << (x * 2) << std::endl; } 
}; 

class MyList { 

public: 
~MyList() { 
    for (auto it = _list.begin(); it != _list.end(); ++it) { 
     delete (*it); 
    } 
    } 

    template <class T> void Add(T* t, void (T::*memberFunction)(int)) { 
    _list.push_back(new Extended<T>(t, memberFunction)); 
    } 

    void CallAll(int g) { 
    for (auto it = _list.begin(); it != _list.end(); ++it) { 
     (*it)->Call(g); 
    } 
    } 

private: 
    std::list<Base*> _list; 
}; 


int main() { 
    MyList myList; 
    Test1 test1; 
    Test2 test2; 
    myList.Add(&test1, &Test1::Fun1); 
    myList.Add(&test2, &Test2::FunX); 
    myList.CallAll(100); 
} 

이를 완벽하게 작동합니다. 내 문제는 목록에서 클래스 및 멤버 함수를 제거하는 방법을 모르겠다는 것입니다. 또한 동일한 클래스와 멤버 함수가 두 번 호출되는 것을 원하지 않습니다. 이는 사실상 동일한 문제입니다. 나는 평등을 위해 Base 클래스의 두 클래스를 검사해야한다. 나에게 void 포인터를주는 가상 함수를 제공 할 수있다.

virtual void* GetPtr() = 0; 

하지만 클래스의 동등성 만 검사합니다. 나는이 클래스의 함수 포인터의 동등성을 검사하는 방법을 알지 못한다.

template <class T> void MyList::Remove(T* t, void (T::*memberFunction)(int)) { 

} 

등이있다.

누군가가 문제의 해결책을 알고 있습니까? 또는이 검사가 불가능합니까?

+2

사이드 노트 - 가상 소멸자를 정의해야합니다. – PiotrNycz

+0

왜 멤버 함수 만 수락합니까? 따라서 코드가 훨씬 더 모호해진다. 정말로 Callable을 수락하고'std :: mem_fn'을 사용하면 정말 멤버 함수 여야합니다. – pmr

+0

C++ 11이므로 std :: mem_fn에 익숙하지 않습니다. 하지만 그것은 std :: mem_fn이 코드를 좀 더 C++로 만드는 것처럼 보입니다. 원래 코드는 Base에 대한 다양한 템플릿을 사용하여 모든 종류의 매개 변수를 허용하는 훨씬 더 복잡합니다. –

답변

0

가상 isEqual 메서드를 Base에 추가하십시오. 그렇지 않으면 당신은 메모리 누수가

class Base { 
public: 
    virtual void Call(int x) = 0; 
    virtual bool isEqual(const Base& other) = 0; 
}; 

template<class T> class Extended : public Base 
{ 

    public: 
     virtual bool isEqual(const Base& other) 
     { 
     const Extended* otherPtr = dynamic_cast<const Extended*>(&other); 
     return otherPtr != nullptr && otherPtr->_ptr == _ptr && otherPtr->_memberFunction == _memberFunction; 
     } 

}; 

그리고 Base에 가상 소멸자를 추가,

그리고 멤버 변수 _ptr의 시작 부분에 undescore을 사용하지 않는다 - 당신이 마지막에 사용해야하는 경우 : ptr_. 일부 맨 앞의 밑줄은 컴파일러 용으로 예약되어 있습니다.

+0

그게 전부 야. 고맙습니다. 왜이 솔루션이 내 마음을 교차시키지 않았는지 궁금합니다. –

+0

선행 밑줄은 반드시 컴파일러 용으로 예약되어 있지는 않습니다. 컴파일러에 예약 된 식별자는 다음 정규 표현식과 일치하는 식별자입니다 :'^ _ [A-Z]. *'와'. * __. *'(후자는 스마일리가 아니며 두 개의 밑줄입니다). –

+0

@MatthieuM. 당신은 맞습니다 - 저는 규칙 "정확한 언더 도르를 사용하지 마십시오"를 정확한 규칙보다 기억하기 쉽도록 취급합니다. – PiotrNycz

관련 문제