Функция, объявленная как Virtual в производном классе, не выполняется, вместо этого выдана ошибка компиляции. Почему? - PullRequest
0 голосов
/ 25 ноября 2018

Я понимаю виртуальную функцию и vTable, поэтому прошу прощения, если задавать тривиальный вопрос ....

Основываясь на концепции vTable и vPtr, объясненной людьми, я понял и ожидаю, что нижепрограмма должна работать, но выдает ошибку.

Постановка задачи: В приведенном ниже примере, согласно пониманию, класс B должен иметь «vTable», содержащий функции f2 () и f3 ().Не так ли?(поскольку f2 () наследуется от класса A, но переопределяется, а f3 делается виртуальным в самом классе B)

, но при вызове функции " obj-> f3 (); "ошибка его выдачи, как показано ниже, мне все еще интересно, почему это так?

ОШИБКА: В функции 'int main ()': 31:10: ошибка: у класса A нет члена с именем 'f3'

// Example program
#include <iostream>
#include <string>

using namespace std;     
class A
{
    public:
    void f1() {cout<<"A::f1"<<endl;}
    virtual void f2() {cout<<"A::f2"<<endl;}
};    

class B: public A
{
    public:
    void f1() {cout<<"B::f1"<<endl;}
    void f2() {cout<<"B::f2"<<endl;}
    virtual void f3() {cout<<"B::f3"<<endl;}
};


int main()
{
    A* obj = new B();
    obj->f1();      // Early Binding (EB)
    obj->f2();      // Late Binding (LB)
    obj->f3();      // Error (though was expecting LB since f3 is virtual)
}

ОШИБКА : В функции 'int main ()': 31:10: ошибка: у класса A нет члена с именем 'f3'

Ответы [ 2 ]

0 голосов
/ 26 ноября 2018

Прежде чем пытаться описать семантику любой инструкции C ++, вам необходимо вернуться к самым фундаментальным концепциям C ++ (которые являются сложным вариантом фундаментальных концепций C): C ++ - это скомпилированный язык со статическимнабрав .

Как и в C, в C ++ имена ищутся и связываются во время компиляции : любое используемое имя должно ссылаться на видимое объявление.Единственные имена, которые могут быть найдены компилятором, это имена в классе, обозначенном выражением.(Выражения являются синтаксическими конструкциями, они существуют во время компиляции .)

В языке со статической типизацией типы выражений являются статическими и вычисляются внутри каждой функции в соответствии ск объявлениям.

C ++ также поддерживает динамический полиморфизм через виртуальные функции;это не делает язык динамически типизированным;основы неизменны: у каждого выражения есть тип, определяемый применением правил на основе его синтаксиса и видимых объявлений (видимых имен объектов, функций и т. д.).

С динамическим полиморфным типомполиморфный объект (объекты существуют в время выполнения ), то есть тип, который был создан (имя класса конструктора, который работал для создания объекта) определяет, какое тело функции являетсявызывается виртуальным вызовом .Иногда это называется поздним связыванием.

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

obj->f3();      // Error (though was expecting LB since f3 is virtual)

Когда obj имеет тип указателя obj->something совпадает с (*obj).something;obj - локальная переменная, определенная как

A* obj = (...something not relevant for the argument...);

, поэтому obj имеет тип A*, а *obj имеет тип A, который является классом, определенным как:

class A
{
    public:
    void f1() {cout<<"A::f1"<<endl;}
    virtual void f2() {cout<<"A::f2"<<endl;}
};

Нет объявления какого-либо члена f3, видимого в классе, обозначенном выражением *obj. Таким образом, вызов неверно сформирован. Он недействителен во время компиляции, и компилятор отклоняет его.

И это весь соответствующий анализ этого плохо сформированноголиния.Остальное не имеет значения в статически типизированном языке.Производные классы, не названные в релевантном коде (который является просто объявленным типом obj и выражением, определяющим, где выполняется поиск по имени, *obj), не имеют значения.Это сущность статической типизации.

Кроме того, создание достоверности кода зависит от других классов, не имеющих прямого имени (классов, которые могут быть типом объекта, созданного во время выполнения,какое-то выражение относится к) сделает невозможным обнаружение даже простой опечатки во время компиляции.

0 голосов
/ 25 ноября 2018

Детали реализации (vtable или нет) не имеют значения.В глазах стандарта (и, следовательно, компилятора) ваш код недопустим, потому что A не имеет метода f3(), а obj имеет тип A*, вот и все.

...