繁体   English   中英

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

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

我一直在一个项目中成功使用Subject-Observer模式。 随着主题观察者和消息类型的数量增加到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的动机具体T_subject可以配对哪些子类,例如RotationObservers应该仅观察RotationSubjects并接收Rotation消息类型(在此示例中T_messageunsigned long )。

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

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

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

我愿意接受完全不同的设计和改进建议。

您要删除const限定符。 没有const_cast和充分的理由,您将无法做到这一点。

您还试图在“错误的”方向上进行转换。 并非每个Observer< RotationSubject, unsigned long>都不一定是RotationObserver ,尽管反之亦然。 您可以使其与dynamic_cast (或static_caststatic_cast )一起使用。

进一步的搜索发现了一些与模板化主题-观察者模式特别相关的有用链接:( https://www.codeproject.com/Articles/3267/Implementing-a-Subject-Observer-pattern-with-templ )( 基于模板的主题观察者模式-我应该使用static_cast还是dynamic_cast )( 我应该在带有模板的主题观察者模式中使用动态转换

以下代码是有效的正确版本。 它是从第一个链接派生的。 根据@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;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM