Способ вызова базового класса

#c #derived-class

Вопрос:

У меня есть следующий код:

 #include<iostream>
using namespace std;

struct Base{
    void f(int x){
        cout<<"B";
    }
};
struct Derived: public Base {
    virtual void f(double x){
        cout<<"D";
    }
};

int main(){
Derived d;
int x = 5;
d.f(x);
Base *pb = amp;d;
pb->f(x);

}
 

Это выводит: DB
Даже несмотря на то, что pb хранит указатель на производный класс. Почему метод
Base класс вызывают?

Комментарии:

1. Вы упускаете virtual метод базового класса. Вы не можете сделать метод виртуальным постфактум; так должно быть с самого начала.

Ответ №1:

Объявление Derived::f виртуального не делает Base::f виртуальным, поэтому при вызове вызывается f указатель на Base then Base::f .

Вы должны объявить метод virtual в Base . Затем он также будет virtual Derived включен , вам не нужно virtual там повторяться. В Derived вы должны использовать override спецификатор следующим образом:

 struct Base{
    virtual void f(int x){
        cout<<"B";
    }
};
struct Derived: public Base {
    void f(double x) override {
        cout<<"D";
    }
};
 

override Спецификатор помогает выявлять ошибки, когда метод на самом деле не override является унаследованным методом. Например, для приведенного выше вы получите сообщение об ошибке в строке:

 source>:10:10: error: 'void Derived::f(double)' marked 'override', but does not override
   10 |     void f(double x) override {
      |          ^
 

Типы параметров должны совпадать, когда вы хотите переопределить.

Этот код выводит ожидаемое DD :

 #include <iostream>

struct Base {
    virtual void f(int x){
        std::cout << "B";
    }
};
struct Derived: public Base {
    void f(int x) override {
        std::cout << "D";
    }
};
 

Обратите внимание, что если вы не используете override , то такие ошибки могут остаться незамеченными. Когда классы определены следующим образом:

 struct Base{
    virtual void f(int x){
        std::cout<<"B";
    }
};
struct Derived: public Base {
    void f(double x) {
        std::cout<<"D";
    }
};
 

Тогда Derived::f не переопределяет Base::f . Он только скрывает это, и результат все равно будет DB .

Живая демонстрация

Ответ №2:

Сначала он выводит D из-за вызова вашей функции производного класса, а затем выводит B, потому что вы просто вызываете функцию базового класса