Множественное наследование: невозможно создать экземпляр абстрактного класса - PullRequest
3 голосов
/ 01 марта 2020

У меня есть это:

class Base {
public:
    Base() {};
    virtual ~Base() = default;

    virtual void Draw() = 0;
};

class Derived_1 {
public:
    Derived_1() {};
    void Draw() { std::cout << "Draw()" << std::endl; };
};

class Derived_2 : public Base, public Derived_1 {
public:
    Derived_2() {};
    ~Derived_2() {};        

    //void Draw() { Derived_1::Draw(); }; <<<<<===--- This works well
};

class Derived_3 : public Derived_2 {
public:
    Derived_3() {};
    ~Derived_3() {};        
};

int main()
{
    Base* d = new Derived_3();
    d->Draw();

    return 0;
}

Я получил ошибку типа "чисто виртуальная функция" Base :: Draw "не имеет переопределения". Я думаю, что проблема в том, что Derived_2 имеет две функции Draw (), одна из которых виртуальная. Однако я не знаю, как это исправить, не добавляя функцию-обертку Draw () в класс Derived_2. Возможно ли это?

Ответы [ 4 ]

5 голосов
/ 01 марта 2020

Когда вы задаете множественное наследование класса Derived_2 (т. Е. Оно происходит от Base и Derived_1), вы говорите, что оно наследует функции-члены от обоих базовые классы.

В этом случае это будет означать, что он имеет два (разных) Draw члена с одинаковыми подписями. Таким образом, чисто виртуальная Draw функция, полученная из Base, будет не переопределена той, которая получена из Derived_1.

Фактически, если вы используете Derived_3* d = new Derived_3(); вместо В вашей первой строке main(), как было предложено, вы все равно получите ошибку «не удается создать абстрактный класс», плюс еще одну строку в соответствии с «неоднозначным доступом Draw ()».

Ваш комментарий закомментирован line, void Draw() { Derived_1::Draw(); }; в Derived_2 классе делает две вещи: (1) устраняет неоднозначность при любом последующем вызове Draw() из Derived_2 класса; и (2) он обеспечивает жизнеспособное переопределение чисто виртуальной функции Draw класса Base.

2 голосов
/ 01 марта 2020

Две функции Draw различны, несмотря на сходство имени и подписи. С таким же успехом они могут иметь два разных имени. Base и Derived_1 не связаны, поэтому Derived_1 Draw не может переопределить Base.

Если Base::Draw не был чисто виртуальным, вызов d->Draw() in main было бы неоднозначно, потому что компилятор не знал бы, какой рисунок вызывать.

Решение - это то, что вы прокомментировали: предоставьте Draw в Derived_2, который будет вызывать тот, который в Derived_1 , (Не относится здесь, но в альтернативе, где Base::Draw не является чисто виртуальным, Derived_2::Draw может потребоваться вызвать функцию Draw в обоих базовых классах.)

1 голос
/ 01 марта 2020

Я думаю, что ваша проблема в том, что вы определили d как класс «Base» вместо класса «Derived_3», поэтому, даже если вы использовали конструктор Производный_3, компилятор ищет определение отрисовки в разделе «База».

0 голосов
/ 01 марта 2020

у вас есть 2 функции с одинаковыми именами и аргументами, что никогда не бывает хорошо. попробуйте либо изменить имя одной из Draw() функций, либо, если вам действительно нужно то же имя, заставить Derived_1 наследовать от Base

...