문제

typedef void (FunctionSet::* Function)();

class MyFunctionSet : public FunctionSet
{
protected:
    void addFunctions()
    {
        addFunction(Function(&MyFunctionSet::function1));
    }

    void function1()
    {
        // Do something.
    }
};

AddFunction 메소드는 기본 클래스의 목록에 함수를 추가합니다.
그런 다음 모든 기능을 호출하도록 열거 할 수 있습니다.

함수 추가를 단순화 (타이핑 작업을 적게 함) 할 수있는 방법이 있습니까?

도움이 되었습니까?

해결책

파생 클래스의 함수에 대한 멤버 함수 포인터를 기본 클래스의 함수에 대한 멤버 함수 포인터에 할당하는 것 같습니다. 글쎄, 그것은 유형 시스템에 구멍을 열기 때문에 금지되어 있습니다. 그것은 놀랍게옵니다 (적어도 나에게는 처음 들었을 때). 읽다 이 답변 이유를 위해.

당신의 실제 질문에 대답하기 위해 - 나는 할 것입니다 addFunction 템플릿 :

void addFunctions() {
    addFunction(&MyFunctionSet::function1);
}

변화 addFunction 이것에 대한 기본 클래스에서 :

template<typename Derived>
void addFunction(void(Derived::*f)()) {
    myFunctions.push_back(static_cast<Function>(f));
}

더 나은 사용 static_cast, 그것은 당신에게 말할 것입니다 Derived 실제로 파생되지 않았습니다 FunctionSet.

다른 팁

이 작업을 수행하여 달성하려는 것을 설명 할 수 있습니까?

이것은 상당히 나쁜 디자인처럼 보입니다. 순수한 가상 함수 1, 각 구현에 대해 서브 클래스 계산 가능성이있는 "Computable"과 같은 추상 클래스 ( "C ++ 인터페이스")를 가질 수는 없으며 MyFuntions 세트가 계산 가능한 세트를 유지하도록합니까?

기능 포인터를 사용하는 특정 이유가 있습니까?

그래서 나는 URI에 동의하지 않는 경향이 있습니다.

관찰자 패턴을 구현하는 경우 원하는 것은 다음과 같습니다.

"Object X가 Y를 수행하면 코드 z를 실행하고 싶습니다".

순전히 추상적 인 클래스를 기반으로하는 접근 방식을 사용하는 것이 가장 좋은 방법은 아닙니다. 모든 이벤트 핸들러에 대해 별도의 클래스 (특히 C ++)가 필요한 것은 과잉입니다. 당신이 Java에서 온다면 그것이 그들이 모든 일을하는 방식입니다. 그러나 Java에는 익명의 클래스 및 "인스턴스"멤버 클래스의 약간 성가신 두 가지 기능이 있습니다. 이를 통해 동일한 클래스에서 여러 이벤트에 대해 여러 핸들러를 정의 할 수 있습니다. "class {"로 메소드를 접두사해야하지만 할 수 있습니다.

C ++에는 익명 클래스 또는 "인스턴스"멤버 클래스가 없습니다. 이는 상태를 공유 해야하는 여러 취급자가있는 경우 이벤트에 대한 추상 클래스를 훨씬 더 번거롭게 만듭니다. 손으로 폐쇄 생성과 동등한 작업을 수행해야하므로 꽤 빨리 짜증을 낼 수 있습니다.

.NET은 기본적으로 안전한 기능 포인터를 입력하는 이벤트 처리에 대의원을 사용합니다. 그들은 이벤트를 처리하기위한 코드를 매우 간단하게 만듭니다. 그러나 C ++의 함수 포인터와 달리 대의원은 멤버 함수 포인터 및 정적 기능 포인터를 통합합니다. 기본적으로 모든 멤버 함수의 "이"매개 변수를 카레로 만들 수 있으며, 정적 기능 포인터처럼 보이는 함수 포인터를 남깁니다. 이는 이벤트를 처리하는 객체의 유형이 이벤트 "인터페이스"의 일부가 아니라는 것을 의미합니다. 그것은 매우 유연하게 만듭니다.

"이"유형이 함수 포인터 유형의 일부이기 때문에 C ++ 멤버 함수 포인터를 사용하여 직접 할 수 없습니다. 따라서 핸들러가 현재 클래스 내에서만 나타나는 것으로 제한합니다.

C ++를위한 최상의 솔루션은 둘 사이의 하이브리드입니다. 당신이 원하는 것은 다음과 같은 일반적인 인터페이스입니다.

class EventHandler
{
public:
    virtual void Handle() = 0;
};

그런 다음 이와 같은 멤버 기능에 대한 구현이 있습니다

template <class T>
class MemberFuncEventHandler : public EventHandler
{
public:


    MemberFuncEventHandler(T * pThis, void (T::*pFunc)()) : m_pThis(pThis), m_pFunc(pFunc)
    {
    }

    void Handle()
    {
        (m_pThis->*m_pFunc)();
    } 
private:
    T* m_pThis;
    void (T::*m_pFunc)();
};

template <class T>
EventHandler * Handler(T * pThis, void (T::*pFunc)())
{
    return new MemberFuncEventHandler<T>(pThis, pFunc);
}

정적 메소드의 핸들러 클래스를 유사하게 정의 할 수도 있습니다. 그런 다음 다음과 같은 일을 할 수 있습니다.

Handlers += Handler(obj, &(c1::foo));
Handlers += Handler(obj, &(c2::bar));
Handlers += Handler(blaa); // for static methods...

추가 연산자를 과부하 할 수 있다고 생각합니다.

콜백 시스템이나 무언가를 만들려고하는 경우 Boost.Signals 라이브러리를 추천합니다. 기본적으로 집계는 기능을 수행하고 (다른 신호 라이브러리와 같은) 기능 그룹을 호출하지만 Boost.bind 및 boost.Function과 함께 작동하도록 설계되었습니다.

예시:

using boost::function
using boost::bind
using boost::signal

void some_other_func();    

Foo a;
Bar b;

signal<void()> sig;

sig.connect(bind(&Foo::foo,&a));
sig.connect(bind(&Bar::bar,&b));
sig.connect(some_other_func);

sig(); // calls -> a.foo(), b.bar(), some_other_func()

또한 차단, 정교한 연결 관리 및 기타 깔끔한 것들을 지원합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top