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

C++ error: invalid conversion from (base class template) to subclass

本文关键字:子类 转换 无效 错误 基类      更新时间:2023-10-16

我一直在项目中使用主题观察者模式。由于主题观察者和消息类型的数量已增长到5 ,因此我发现自己为每个复制了相同的代码模式。我正在尝试切换到主题观察者模式的类模板。但是我陷入了我无法解决的编译器错误(尽管做出了努力(:

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作为原因,没有成功。

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

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

您正在丢弃const预选赛。没有const_cast和一个充分的理由,您将无法做到这一点。

您还试图转换为"错误"方向。并非每个Observer< RotationSubject, unsigned long>都必须是RotationObserver,尽管相反是正确的。您可以通过dynamic_cast(或static_cast和Promise(使其使用。

进一步搜索出现了一些有用的链接,这些链接与模板 - 观察者模式:(https://www.codeproject.com/articles/3267/implementing-a-subject-observer-pattern-with-templ((基于模板的主题观察者模式 - 我应该使用static_cast或dynamic_cast((我应该使用模板的主题观察者模式中的动态铸造(

以下代码是有效的更正版本。它源自第一个链接。根据@boundaryIblosition的答案,它在模板主题中使用static_cast :: notifyObservers((方法在获取指向主题子类的指针。我对这个概念不满意100%,但它有效。根据我的理解,魔术酱是Subject中奇怪的重复模板图案的使用。特别是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;
}