Вызывается виртуальный метод базового класса вместо реализации дочернего переопределения - PullRequest
1 голос
/ 06 мая 2020

Я пишу интегратор ODE с BOOST :: ODEINT. Для этого требуется, чтобы в классе с logi c была перегружена operator () с этой сигнатурой «void operator () (const std :: vector & x, std :: vector & dxdt, double t)».

Я сделал вид, что написал абстрактный класс, который инкапсулирует общие логические модели c и интегратора c, а базовый дочерний элемент будет реализовывать некоторые специфические c аспекты (например, систему, необходимую ODEINT).

Я обнаружил, что не могу реализовать как абстрактный класс, потому что код не компилируется, так как не смог написать шаблон интегратора. Поэтому я удалил все чистые виртуальные функции, затем код хорошо скомпилировался, но я всегда получаю метод базового класса, вызываемый вместо дочерней реализации.

#include <vector>
#include <iostream>
#include <boost/numeric/odeint.hpp>

class BaseClass {
public:
    virtual void ode(const std::vector<double> &x, std::vector<double> &dxdt, double t) {
        std::cout << "Not expected." << std::endl;
    };

    void operator() (const std::vector<double> &x, std::vector<double> &dxdt, double t) {
        std::cout << "BaseClass" << std::endl;
        this->ode(x, dxdt, t);
    };

    void integrate() {
        double t = 0, dt = 0.5;
        std::vector<double> state(2, 0.0);
        boost::numeric::odeint::runge_kutta4<std::vector<double>> stepper;
        stepper.do_step(*this, state, t, dt);
    };
};

class DerivedClass : public BaseClass {
public:
    virtual void ode(const std::vector<double> &x, std::vector<double> &dxdt, double t) {
        std::cout << "Expected." << std::endl;
    };
};

void main() {
    DerivedClass d;
    d.integrate();
}

Это дает

Base Class
Not expected

Я также пытался создать виртуальный метод operator (), но выдает тот же результат.

Пока я пишу это, я думаю, что собираюсь отделить logi c интегратора от модели, но я бы хотел чтобы знать, что это происходит.

Всем спасибо!

1 Ответ

1 голос
/ 06 мая 2020

Цитата из соответствующей документации :

Таким образом, все системные функции и наблюдатели передаются по значению . Например, если вы вызываете метод do_step определенного шагового двигателя или функции интеграции, ваша система и ваш шаговый двигатель будут переданы по значению.

Проблема в том, что динамический c полиморфизм работает только тогда, когда вы вызываете виртуальные функции через указатели / ссылки. Чтобы выполнить sh это, оберните *this в std::ref, как предложено в комментариях (или boost::ref, как предлагается в исходной документации).

Обратите внимание, что эта работа, поскольку std::reference_wrapper определяет функцию - вызов operator(), который вызывает то же самое для базового объекта. (С именованной функцией-членом этот подход не сработает.)


Пример простой живой демонстрации, в которой сравниваются оба случая: здесь .

...