статическое и динамическое разрешение в C ++ - PullRequest
0 голосов
/ 01 мая 2018

Текст, за которым я следую, говорит:

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

Теперь рассмотрим следующую программу:

#include <iostream>

class Mainclass{
    protected: 
        double length{1.0};
        double width{1.0};
        double height{1.0};

    public:
        Mainclass(double lv, double wv, double hv):length{lv}, width{wv}, height{hv}{
            std::cout<<"Three args box ran"<<std::endl;
        }

        void showVolume() const{
            std::cout<<"Mainclass usable volume is: "<<Volume()<<std::endl;
        }

        virtual double Volume() const{
            return length*width*height;
        }

};


class Derivedclass: public Mainclass{
    public: 
        Derivedclass(double lv, double wv, double hv): Mainclass{lv, wv, hv}{}

        double Volume() const{
            return 0.85*length*width*height;
        }

};

int main(){
    Mainclass first{20.0, 30.0, 40.0};
    Derivedclass second {20.0, 30.0, 40.0};

    first.showVolume();
    second.showVolume();
}   

Выход:

Three args box ran
Three args box ran
Mainclass usable volume is: 24000
Mainclass usable volume is: 20400

Здесь я вызываю базовый класс и объекты производного класса через их экземпляры объектов, а не через указатель. Но похоже, что функция решается динамически. Был ли текст неправильным? Если нет, то что это значит?

1 Ответ

0 голосов
/ 01 мая 2018

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

Это предложение не столько описывает правило языка C ++, сколько разрешено использовать компиляторам ярлыков.

Вы звоните showFunction прямо по именам объектов. Итак, предположим, что showFunction были объявлены виртуальными. Компилятор знает точные типы объектов, называемые first и second: они никак не могут быть объектами какого-либо другого типа. Таким образом, хотя язык говорит, что любая переопределяющая функция должна вызываться first.showVolume() и second.showVolume(), нет никакого возможного способа, которым результатом будут какие-либо функции, отличные от тех, которые компилятор может найти немедленно, поэтому на самом деле не нужно помещать какие-либо код для определения, какую функцию вызывать в результирующей программе. Правильная функция Mainclass::showVolume() (или Derivedclass::showVolume(), если она существовала) может вызываться напрямую, что может быть несколько более эффективным.

Цитата не относится к вызову Volume() внутри showVolume(). Поскольку Volume называет нестатический член, Volume() означает то же самое, что и this->Volume(). this - указатель, который может указывать или не указывать на объект, полный тип которого соответствует типу Mainclass* const указателя. Так что в этом случае компилятор должен выполнить динамическое разрешение, чтобы определить, какую функцию вызывать.

Но еще одна вещь, на которую следует обратить внимание: это правда, что вы можете получить динамическое разрешение только через указатель или ссылку, но это не так, вы всегда получаете динамическое разрешение через указатель или ссылку. Когда функция называется «квалифицированным идентификатором» с использованием токена ::, язык говорит, что вызываемая функция определяется статически, а переопределения игнорируются. Например, если ваш код в showVolume() изменился на использование Mainclass::Volume() или this->Mainclass::Volume(), вы увидите, что он никогда не вызывает Derivedclass::Volume.

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