Встраивание виртуальной функции С++, когда производный класс является окончательным?

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

class Base {

    public:

        inline virtual void x() = 0;
}

class Derived final : Base {

    public:

        inline virtual void x(){
            cout << "inlined?";
        }
}

int main(){
    Base* a;
    Derived* b;

    b = new Derived();
    a = b;

    a->x(); //This can definitely not be inlined.
    b->x(); //Can this be inlined?
}

С моей точки зрения, компилятор должен знать окончательный тип a во время компиляции, так как это окончательный класс. Можно ли встроить виртуальную функцию в этом случае? Если нет, то почему? Если да, то делает ли это gcc-компилятор (соответственно avr-gcc)?

Спасибо!


person DocValle    schedule 01.04.2018    source источник
comment
Компилятор может выполнять любую оптимизацию, не дающую видимых результатов. В этом случае не будет никаких наблюдаемых результатов от встраивания вызова метода производного класса, поэтому компилятору разрешено встраивать его. Будет ли это, зависит от компилятора.   -  person Sam Varshavchik    schedule 01.04.2018
comment
Другой альтернативой является использование статического полиморфизма во время компиляции вместо динамического полиморфизма во время выполнения. Я предпочитаю последнее, но если вы сильно ограничены во встроенной среде, возможно, стоит использовать первое.   -  person Eljay    schedule 01.04.2018


Ответы (1)


Первый шаг называется девиртуализацией; где вызов функции не проходит через виртуальную диспетчеризацию.

Компиляторы могут и действительно девиртуализируют конечные методы и методы конечных классов. В этом почти вся суть финала.

После девиртуализации методы могут быть встроены.

Некоторые компиляторы иногда могут подтвердить статический тип *a и даже девиртуализовать его. Это менее надежно. Проводник компилятора Godbolt может быть полезен, чтобы понять, какие конкретные оптимизации могут произойти и как они могут дать сбой.

person Yakk - Adam Nevraumont    schedule 01.04.2018
comment
Спасибо за объяснение. Почему указатель/ссылка отличается от объекта с точки зрения компилятора? - Разве оба не имеют четко определенного типа? - person DocValle; 01.04.2018
comment
@docvalle фактическое значение объекта имеет фиксированный динамический тип (равный его статическому типу). Указатели на не окончательные типы могут иметь различный динамический и статический тип. - person Yakk - Adam Nevraumont; 01.04.2018