Si, perché il dynamic_cast<> è abbastanza lento rispetto a una chiamata virtuale, per cui si può "emulare" tramite una enum, una funzione virtuale e uno static_cast<>. Ma non entro nei dettagli perché non è l'oggetto del thread.In particolare mi interessava sapere se il modo in cui individuo il tipo del subject passato col metodo setSubject e' corretto (uso del dynamic_cast) o si puo' fare altrimenti, usando ad esempio typeid, ma da quanto letto in giro mi pare sconsigliato.
Io ho solo riportato quanto hai scritto. Immagino per estendere il pattern.Qui mi perdo io: in che senso parlo di piu' observer?
La strada "accademica" è interessante ma lunga.Se poi esistono altre strade percorribili, per le mie necessita', se non stravolgono la logica e non sono complicate, conoscere roba nuova puo far solamente bene, altrimenti, essendo programmi per uso personale, non sono alla disperata ricerca di prestazioni o che altro, una volta che funzionano, va bene.
La cosa più semplice è mettere in overload la funzione update() affinché riceva il dato corretto.
Ti posto un esempio. Nel main puoi vedere come i metodi invocati sono solo quelli dell'interfaccia Observer e Subject.
Per quanto riguarda lo std::set<>, il suo scopo è solo quello di avere una singola istanza di quanto gli viene passato, cosa che con il vector (di inizio thread) diventa complicato.
codice:class Subject; // forward declaration necessarie per i metodi in overload class DerSubject1; class DerSubject2; class DerSubject3; class Observer { public: virtual ~Observer() {}; void setSubject(Subject* sub); void removeSubject(Subject* sub); // update in overload per tipo di subject da ridefinire // nelle derivate da Observer virtual void update(DerSubject1* subject) = 0; virtual void update(DerSubject2* subject) = 0; virtual void update(DerSubject3* subject) = 0; protected: Observer() {}; std::set<Subject*> mSubjects; }; class Subject { public: virtual ~Subject() {}; void attach(Observer* observer) { mObserverList.insert(observer); } virtual void detach(Observer* observer) { mObserverList.erase(observer); } virtual void notify()= 0; protected: Subject() {}; std::set<Observer*> mObserverList; }; // occorre metterle qui perché hanno bisogno della definizione delle // funzioni di Subject void Observer::setSubject(Subject* sub) { sub->attach(this); mSubjects.insert(sub); } void Observer::removeSubject(Subject* sub) { sub->detach(this); mSubjects.insert(sub); } // la funzione notify dev'essere ridefinita nelle singole // derivate da Subject perché dev'essere propagato // il tipo di dato reale. class DerSubject1 : public Subject { public: // per l'interfaccia Subjects void notify() { for( auto it : mObserverList) { it->update(this); } } // funzione propria std::string getMyName1() { return "DerSubject1"; } }; class DerSubject2 : public Subject { public: // per l'interfaccia Subjects void notify() { for(auto it : mObserverList) { it->update(this); } } // funzione propria std::string getMyName2() { return "DerSubject2"; } }; class DerSubject3 : public Subject { public: // per l'interfaccia Subjects void notify() { for(auto it : mObserverList) { it->update(this); } } // funzione propria std::string getMyName3() { return "DerSubject3"; } }; class DerObserverMoreSubject : public Observer { public: void update(DerSubject1* subject) override { std::cout << "DerObserverMoreSubject observes " << subject->getMyName1() << std::endl; }; void update(DerSubject2* subject) override { std::cout << "DerObserverMoreSubject observes " << subject->getMyName2() << std::endl; } void update(DerSubject3* subject) override { std::cout << "DerObserverMoreSubject observes " << subject->getMyName3() << std::endl; } }; using namespace std; int main(int argc, char* argv[]) { DerObserverMoreSubject doms; DerSubject1 ds1; DerSubject2 ds2; DerSubject3 ds3; Observer* ob = &doms; Subject* s1 = &ds1; Subject* s2 = &ds2; Subject* s3 = &ds3; ob->setSubject(s1); ob->setSubject(s2); ob->setSubject(s3); s1->notify(); s2->notify(); s3->notify(); }