2017-01-05 6 views
3

몇 년 전 C++에 대해 많이 알기 전에 경험있는 프로그래머 동료와 이벤트 시스템을 만드는 것에 대해 이야기하고있었습니다. 그는 콜백 함수를 전달할 수 있도록 함수 포인터를 전달해야 할 필요성에 중점을 두는 것처럼 보였습니다.C++, 함수 포인터 대 관찰자 패턴

그러나 요즘에는 어떤 종류의 이벤트 시스템을 구현해야 할 때마다 간단히 의사 인터페이스 클래스를 생성하고이를 상속 받아 subscriber/observer 패턴을 사용하여 메서드를 재정의합니다. 이벤트를 배포 할 수 있습니다.

저는 지금까지는 함수 포인터를 사용할 필요가 거의 없었습니다. 분명히 위와 같은 상황에서는 아닙니다. 필자가 실제로 함수 포인터를 사용해야했던 유일한 상황은 명시 적으로 전달되어야하는 다른 사람의 .dll과 인터페이스 할 때입니다.

언제 구독자/관찰자 패턴 대신 함수 포인터를 사용해야합니까?

둘 중 하나를 사용하는 것이 좋습니다. (아마 관찰자 패턴이 함수 포인터보다 좋지 않은 경우가있을 것입니다).

누군가 통찰력을 공유 할 수 있습니까? 이것에 대해 더 많은 경험을하는 것이 좋을까요? (앞서 언급 한 동료가 다른 사업으로 이전했으며 연락이 끊겼습니다). 나는이 주제에 두뇌를 계속 두르고 관찰자 패턴과 인터페이스를 사용하는 것이 더 낫지 않을 때를 생각할 수 없다.

감사합니다.

(실제로는 작동하지 않을 수 있습니다, 완전히 내 머리 위로 떨어져, 테스트없이 작성) 나는 종종 자신이 쓰는 찾을 것 클래스의 예 :

class NotifierListener { 

friend class Notifier; 
private: 
vector<NotifierListener*> mListeners; 

protected: 
void subscribe(NotifierListener* _subscriber) {mListeners->push_back(_subscriber);} 
virtual void onNotification(); 
} 

class Notifier : public NotifierListener { 

private: 
void doSomethingAndNotify() { 

... 
if (mListeners.size() > 0) { 
for (int i = 0; i < mListeners.size(); ++i) { 

mListeners[i]->onNotification(); 
} 
} 

} 
} 

class Something : public NotifierListener { 

Something() { subscribe(this); } 

void onNotification() { 

cout << "I got notified\n" << endl; 
} 
} 
+2

함수 포인터를 통한 콜백은 관찰자 패턴을 구현할 수도 있습니다. 구현을 보여주는 몇 가지 코드로 질문을 설명해야합니다. – wasthishelpful

+0

코드 그림에 가치와 명확성이 추가된다는 것에 동의합니다. 그러나 여기서 나의 문제는 특정 코드 구현의 예제를 원하기보다는 '어떻게'가 아닌지에 대한 일반적인 단어 설명에 더 관심이 있다는 것입니다. 필자는 가상 코드로 작성된 코드가 명확하고 분명하지 않은 코드를 작성할 수 없다고 생각합니다. –

답변

2

함수 포인터가 좀 더 효율적입니다. 이제 인터페이스에 대한 포인터를 전달합니다. 인터페이스는 일반적으로 vtable에 대한 포인터를 포함합니다. 그리고 vtable에는 함수 포인터가 있습니다. 3 수준의 간접 참조이며 참조 수준이 낮습니다.

[*] 다른 구현도 가능하지만 비슷한 오버 헤드가 있습니다.

2

바와 같이 wasthishelpful, 상속에 의해 지적되었다 함수 포인터는 옵저버 패턴을 구현하는 두 가지 방법입니다.

함수 포인터 (또는 특히 C++ 11의 std::function과 같은)를 사용하는 주된 이점은 유연성이 향상되었습니다. 관찰 클래스는 인터페이스를 구현할 필요가 없으며 호출되는 멤버 함수를 임의로 명명 할 수 있습니다. 독립적 인 함수 또는 관찰자 인터페이스를 구현할 수 있도록 수정하고 싶지 않거나 수정할 수없는 객체의 멤버를 호출 할 수도 있습니다.

반면에 상속을 사용하는 것이 더 간단하고 간단합니다. 하지만 그 외에는 함수 포인터 접근법에 대한 이점을 생각할 수 없습니다.

1

Observer Pattern에서 수신자는 이벤트를 수신 할 때 어떤 조치를 취할 엔터티입니다. 대부분의 경우 이러한 엔터티는 개별 작업을 수행하고 이벤트를 수신하고 상태 인에 따라 서로 다른 동작을 호출합니다. 그래서 더 나은 선택은 구체적인 객체가 리스너가되어야한다는 것입니다. 왜냐하면 객체는 개별적인 상태를 가지고 있기 때문입니다. 이러한 상태를 일관성있게/완벽하게 (함수 포인터를 사용하여 호출되는) 순수 함수를 사용하여 유지하는 것은 약간 어렵습니다.