Полиморфный класс-член для не виртуальной базы - PullRequest
5 голосов
/ 02 ноября 2019

Во-первых, если все из ответов на полиморфизм, которые я найду, это всегда будет выглядеть так: «если базовая функция не является виртуальной, а производный объект хранится в указателе типа base, то вы не можете вызвать производную функцию». Но они никогда не говорят вам, что делать, когда вы хотите сделать именно это. И это то, что мне нужно сделать.

У меня есть базовый класс B, который я не могу контролировать. Это открытый исходный код (TwoWire из библиотеки Arduino), и он не будет работать для других, если я сделаю локальные изменения.

У меня есть производный класс D и пользовательский класс U, который я оба контролируюover.

По сути, я хочу, чтобы пользователь прозрачно использовал мой класс U с B или D в качестве параметра, сохранил его в члене и использовал в функциях-членах.

Моя тщетная попытка до изучения virtual требуется для базового класса:

#include <iostream>

using namespace std;

class B {
public:
    void foo() { cout << "base foo\n"; };
};

class D : public B {
public:
    void foo() { cout << "derived foo\n"; };
};

class U {
public:
    U(B *b) : b(b) { }
    void work() { b->foo(); }
private:
    B *b;
};

int main() {
    B b; U u1{&b}; u1.work(); // "base foo"
    D d; U u2{&d}; u2.work(); // I need this to somehow print "derived foo"
    return 0;
}

Я мог бы решить эту проблему, создав абстрактный класс-обертку и два подкласса, которые обертывают либо B или D, но это приведет к тому, что общее число пользовательских классов будет равно 5. Я надеюсь найти решение только для 2 пользовательских классов (или не более 3).

NB Я только начинаюизучать C ++, исходя из Java

1 Ответ

3 голосов
/ 02 ноября 2019

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

#include <functional>

class U {
public:
    template <class C>
    U(C* p)
        : f{[p]{ p->foo(); }}
    {
    }
    void work()
    {
        f();
    }
private:
    std::function<void()> f;
};

( live demo )

Обратите внимание, что функции в Java являются виртуальными по умолчанию. Не в C ++.

...