Есть ли другой способ предотвратить вызов производного метода из суперкласса вместо базового класса, например, с помощью ключевого слова или чего-то еще? - PullRequest
2 голосов
/ 02 мая 2020

Поскольку я практикую C ++ с некоторыми из моих коллег, один из них "столкнулся с ошибкой" в производном классе. Короче говоря, он вызывал базовый метод (callFoo) и ожидал, что он вызовет A::Foo(), но вместо этого он получил B::Foo().

Вот полный пример того, что я на самом деле спрашиваю , Я действительно не знаю, как объяснить лучше, чем это. Я действительно нашел решение, но это решение неудобно; это делает код вроде «санирующим» для будущих расширений наших классов. Есть ли другие доступные решения? (Может быть, ключевое слово?)

nb. Пример является исключительно демонстративным: в исходном примере callFoo() был operator= для Class A. Я изо всех сил старался упростить его.

Пример 1: Нежелательное поведение

#include <iostream>

class A{
    public:
        virtual void Foo(){
            std::cout<<"A Foo\n";
        }

        virtual void callFoo(){
            Foo();
        }
};

class B: public A{
    public:
        virtual void Foo() override{
            std::cout<<"B Foo\n";
        }
};


int main(){
    B mB;

    mB.Foo();
    mB.callFoo();

    return 0;
}

Пример 2: Неидеальное исправление; Есть ли другие решения?

class A{
    public:
        virtual void Foo(){
            std::cout<<"A Foo\n";
        }

        virtual void callFoo(){
            A::Foo();
        }
};

1 Ответ

2 голосов
/ 03 мая 2020

Понятно, что вы создаете объект класса Derived и пытаетесь вызвать функцию callFoo (), присутствующую в базовом классе. Я постараюсь визуализировать этот шаг за шагом:

  1. B mB ---> Поскольку мы создаем объект производного класса , VPtr будет укажите Vtable производного класса.
  2. mB.callFoo (); ---> Vptr по-прежнему указывает на VTable класса Derived. Поскольку объект пытается вызвать callFoo (), он не нашел запись в VTable из производного класса . Вызывает callFoo () базового класса. Теперь вот основной улов , Foo () вызывается из тела callFoo (), но, как уже упоминалось ранее, он будет искать запись этой функции в VTable производного Класс и, следовательно, он вызовет производный класс Foo ().

Следовательно, нам нужно явно сказать компилятору, что нам нужна базовая версия метода и использовать A :: Foo () для вызова метода базового класса.

Для получения дополнительной информации о VTable и VPtr есть полезная ссылка в переполнении стека: VPtr и VTable In Depth C ++

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...