Ошибка "чисто виртуальный метод вызван", когда этот метод был переопределен - PullRequest
0 голосов
/ 21 сентября 2019

Я пытаюсь попрактиковаться в «Шаблоне дизайна наблюдателя».Когда я думал, что чистый виртуальный метод реферата был переопределен его производным классом, произошла ошибка.

В независимом файле есть наблюдатель, который является абстрактным классом:

#ifndef DESIGN_PATTERNS_OBSERVER_H
#define DESIGN_PATTERNS_OBSERVER_H

#include "subject.h"

class Subject;

class Observer{
protected:
    Observer();

public:
    virtual ~Observer();
    virtual void update(Subject *the_changed_subject) = 0;

};

Observer::Observer() {}

Observer::~Observer() {}

#endif //DESIGN_PATTERNS_OBSERVER_H

ObserverОпределяется чисто виртуальный метод «update», который переопределяет следующим образом:

#ifndef DESIGN_PATTERNS_CONCRETE_OBSERVER_H
#define DESIGN_PATTERNS_CONCRETE_OBSERVER_H

#include <iostream>
#include "observer.h"
#include "concrete_subject.h"

class ConcreteObserver : public Observer{
public:
    void update(Subject *the_changed_subject) override {
        auto cs = dynamic_cast<ConcreteSubject *>(the_changed_subject);
        std::cout << "status changed to " << cs->get_status() << std::endl;
    }

};

#endif //DESIGN_PATTERNS_CONCRETE_OBSERVER_H

. Также существует субъект, который также является абстрактным классом. Ошибка «чисто виртуальный метод», вызванный «происходит» в методе «уведомить», гдеЯ отметил

При отладке кажется, что «notify» использует «обновление» Observer, а не ConcreteObserver.

Однако в основной функции _observers должны хранить указатели ConcreteObservers, которые переопределяют «update».

#ifndef DESIGN_PATTERNS_SUBJECT_H
#define DESIGN_PATTERNS_SUBJECT_H

#include <list>
#include "observer.h"


class Subject {
private:
    std::list<Observer*> *_observers;

protected:
    Subject();

public:
    virtual ~Subject();
    virtual void attach(Observer*);
    virtual void detach(Observer*);
    virtual void notify();
};

Subject::Subject() {
    _observers = new std::list<Observer*>;
}

Subject::~Subject() {
    delete _observers;
}

void Subject::attach(Observer *o) {
    _observers->push_back(o);
}

void Subject::detach(Observer *o) {
    _observers->remove(o);
}

void Subject::notify() {
    for (Observer* observer : *_observers) {
//here is where error comes out, found by debug
        observer->update(this);
    }
}

#endif //DESIGN_PATTERNS_SUBJECT_H

И у него есть производный класс "ConcreteSubject":

#ifndef DESIGN_PATTERNS_CONCRETE_SUBJECT_H
#define DESIGN_PATTERNS_CONCRETE_SUBJECT_H

#include "subject.h"

class ConcreteSubject : public Subject {
private:
    int status;
public:
    ConcreteSubject() {
        status = 0;
    }
    void set_status(int s) {
        this->status = s;
        Subject::notify();
    }
    int get_status() {
        return status;
    }

};

#endif //DESIGN_PATTERNS_CONCRETE_SUBJECT_H

Основная функция:

#include <iostream>
#include <vector>
#include "singleton.h"
#include "observer/concrete_subject.h"
#include "observer/concrete_observer.h"

void test2() {
    ConcreteSubject concreteSubject;
    std::vector<ConcreteObserver> observers;
    for (int i = 0; i < 5; ++i) {
        ConcreteObserver observer = ConcreteObserver();
        concreteSubject.attach(&observer);
        observers.push_back(observer);
    }
    concreteSubject.set_status(2);
}

int main() {
    test2();
    return 0;
}

Как я уже упоминал ранее, _обсерверы суперкласса ConcreteSubject Subjectдолжны храниться указатели ConcreteObservers, которые уже переопределяют «обновление».Я не понимаю, почему по-прежнему вызывается «обновление» в Observer.

Вот еще одна странная вещь. Я делаю небольшой тест с почти такими же отношениями классов, которые я показал. Но ошибок не было.

class ABaseA{
public:
    virtual void do_some() = 0;
};

class MidA : public ABaseA{
public:
    void do_some() override {
        cout << "real do some" << endl;
    }
};

class ABaseB{
private:
    list<ABaseA*> *bases;
public:
    ABaseB() {
        bases = new list<ABaseA*>();
    }

    virtual ~ABaseB() = default;

    virtual void add(ABaseA* item) {
        bases->push_back(item);
    }

    virtual void do_active() {
        for(ABaseA *p : *bases) {
            p->do_some();
        }
    }
};

class MidB : public ABaseB{

public:
    MidB() = default;
    void active() {
        ABaseB::do_active();
    }
};

void test3() {
    MidA midA;
    MidB midB;
    midB.add(&midA);
    midB.active();
}

Разница лишь в том, что этот код находится в одном файле.

1 Ответ

1 голос
/ 21 сентября 2019

В файле Subject.h вы должны быть переданы ниже кода в Subject.cpp:

Subject::Subject() {
    _observers = new std::list<Observer*>;
}

Subject::~Subject() {
    delete _observers;
}

void Subject::attach(Observer *o) {
    _observers->push_back(o);
}

void Subject::detach(Observer *o) {
    _observers->remove(o);
}

void Subject::notify() {
    for (Observer* observer : *_observers) {
//here is where error comes out, found by debug
        observer->update(this);
    }
}

Также вы должны добавить class Observer; в верхней части Subject.h

#include <list>
#include "Observer.h"

class Observer; //you should be add this line
class Subject {
private:
    std::list<Observer*> *_observers;

protected:
    Subject();

public:
    virtual ~Subject();
    virtual void attach(Observer*);
    virtual void detach(Observer*);
    virtual void notify();
};
...