C ++错误:从(基类模板)到子类的转换无效

时间:2017-05-04 11:32:18

标签: c++

我一直在项目中成功使用Subject-Observer模式。随着Subject-Observer和消息类型的数量增长到5+,我发现自己为每个代码模式重复相同的代码模式。我正在尝试切换到Subject-Observer模式的类模板。但我仍然遇到一个我无法解决的编译错误(尽管付出了努力):

Building file: ../main.cpp
Invoking: GCC C++ Compiler
g++ -std=c++0x -O3 -Wall -c -fmessage-length=0 -MMD -MP -MF"main.d" -MT"main.d" -o "main.o" "../main.cpp"
../main.cpp: In instantiation of ‘Observer<T_subject, T_message>::~Observer() [with T_subject = RotationSubject; T_message = long unsigned int]’:
../main.cpp:49:7:   required from here
../main.cpp:39:15: error: invalid conversion from ‘Observer<RotationSubject, long unsigned int>* const’ to ‘RotationObserver*’ [-fpermissive]
  ~Observer(){ subject->UnregisterObserver( this ); }
           ^
../main.cpp:10:7: error:   initializing argument 1 of ‘void Subject<T_observer, T_message>::UnregisterObserver(T_observer*) [with T_observer = RotationObserver; T_message = long unsigned int]’ [-fpermissive]
  void UnregisterObserver(  T_observer*  observer ){
   ^
make: *** [main.o] Error 1

最小的工作示例代码是:

#include <vector>

template <class T_observer, typename T_message> class Subject
{
public:
void RegisterObserver( T_observer* observer ){
    observers.push_back(observer);
}

void UnregisterObserver(  T_observer*  observer ){
    for (auto itr = begin(observers); itr != end(observers); itr++){
        if (*itr == observer){
            itr = observers.erase(itr);
            if (itr == observers.end()) break;
        }
    }
}

void NotifyObservers( T_message message ){
    for(auto const& itr : observers){
        itr->ReceiveMessage( message );
    }
}

std::vector < T_observer * > observers;
};


template <class T_subject, typename T_message> class Observer
{
public:

Observer( T_subject* subject )
: subject( subject )
{
    subject->RegisterObserver( this );
}

~Observer(){ subject->UnregisterObserver( this ); }

virtual void ReceiveMessage( T_message message ) {};
// Observer sub-classes define ReceiveMessage

T_subject* subject;
};

class RotationSubject;// forward declaration prevents circular dependency

class RotationObserver : public Observer< RotationSubject, unsigned long>
{
public:
RotationObserver( RotationSubject* rotation_subject );
};

class RotationSubject : public Subject< RotationObserver, unsigned long>
{ };

int main(int argc, char * argv[]){
RotationSubject* pRotSubject = new RotationSubject( );
RotationObserver* pRotObserver = new RotationObserver( pRotSubject );
pRotObserver->~RotationObserver();
return 0;
}

目的是定义从这些基类模板派生的子类,如RotationSubjectRotationObserver所示。类型标识符T_observerT_subject的动机是具体关于哪些子类可以配对,例如RotationObservers只应观察RotationSubjects,并接收轮播消息类型(在此示例中T_messageunsigned long。)

如果我正确阅读了错误消息,Observer<RotationSubject, long unsigned int>* const a RotationObserver*,或者编译器不知道如何转换。

我探讨了循环依赖和const作为原因,但没有成功。

请帮助我了解此错误消息的原因,并在可能的情况下进行最小化修改。这是我的主要问题。

我对完全不同的设计持开放态度,并提出改进建议。

2 个答案:

答案 0 :(得分:2)

您正在放弃const限定词。如果没有const_cast这是一个很好的理由,你就无法做到这一点。

你也试图转换错误&#34;方向。并非每个Observer< RotationSubject, unsigned long>都必须是RotationObserver,尽管反之亦然。您可以使用dynamic_cast(或使用static_cast和承诺)。

答案 1 :(得分:1)

进一步搜索显示了一些与模板化主观察器模式具体相关的有用链接: (https://www.codeproject.com/Articles/3267/Implementing-a-Subject-Observer-pattern-with-templ) (Template based Subject Observer pattern - Should I use static_cast or dynamic_cast) (Should I use dynamic cast in the subject observer pattern with templates

以下代码是有效的更正版本。它源自第一个链接。根据@BoundaryImposition的答案,它在模板化的Subject :: NotifyObservers()方法中使用static_cast来获取指向 Subject子类的指针。我对这个概念不是很满意,但它确实有效。根据我的理解,魔法酱是使用Subject中的Curiously Recurring Template Pattern。具体为class Temperature : public Subject<Temperature>(为清楚起见,删除了第二个模板标识符)。在我使用class RotationSubject : public Subject<RotationObserver>之前,这是一个完全不同的继承。 Observer子类PanicSiren也有不同的继承。

请注意,我的模板会将RegisterObserverUnregisterObserver移至Observer ctor和dtor。不是必需的,只是我喜欢的方式。我还添加了消息类型模板标识T_message,它允许各种消息类型。

我很高兴,因为预期的设计是在没有大量重写的情况下实现的:)。

#include <vector>
#include <iostream>

template <typename T_subject, typename T_message> class Observer{
public:
    Observer( T_subject* subject ) : subject(subject) { subject->RegisterObserver( *this ); }
    virtual ~Observer() { subject->UnregisterObserver( *this ); }
    virtual void ReceiveMessage( T_subject* subject, T_message message ) = 0;// =0 requires subclasses to define
    T_subject* subject;
};

template <class T_subject, class T_message> class Subject{
public:
    virtual ~Subject() {}
    void NotifyObservers( T_message message ){
        typename std::vector<Observer<T_subject,T_message> *>::iterator it;
        for ( it=m_observers.begin(); it!=m_observers.end(); ++it){
            T_subject* this_subject_subclass = static_cast<T_subject*>(this);// pointer to _subclass_ type, curiously not yet defined ;)
            (*it)->ReceiveMessage( this_subject_subclass, message );
        }
    }

    void RegisterObserver( Observer<T_subject,T_message> &observer ){
        m_observers.push_back( &observer ); }

    void UnregisterObserver( Observer<T_subject,T_message> &observer ){
        for (auto itr = begin(m_observers); itr != end(m_observers); itr++){
            if (*itr == &observer){
                itr = m_observers.erase(itr);
                if (itr == m_observers.end())   break;
            }
        }
    }
private:
    std::vector<Observer<T_subject,T_message> *> m_observers;
};

class Temperature : public Subject<Temperature,unsigned long> {};

class PanicSiren : public Observer<Temperature,unsigned long>
{
public:
    PanicSiren(Temperature* subject)
    : Observer<Temperature,unsigned long>::Observer(subject) {}
    void ReceiveMessage( Temperature *subject, unsigned long message ){
        std::cout << "Temperature changed to " << message <<", sounding the siren"
                << std::endl;
    }
};

int main(int argc, char * argv[]){
    Temperature* temp = new Temperature();
    PanicSiren* panic = new PanicSiren( temp );
    temp->NotifyObservers( 42 );
    return 0;
}