Получение указателя на (чистую) виртуальную функцию из экземпляра базового класса - PullRequest
3 голосов
/ 12 марта 2019

У меня есть следующий код c ++ 11, который работает, хотя я ожидал, что он потерпит крах или даже не скомпилируется. Получение указателя на чисто виртуальную функцию-член должно возвращать нулевой или недействительный указатель или должно быть заблокировано компилятором. Я хотел бы понять, почему это работает.

Я знаю, что есть другие (лучшие) способы кодирования этого, это чисто теоретический вопрос для понимания того, что делает синтаксис.

#include <iostream>
#include <functional>

class Abstract
{
public:
    void foo()
    {
        auto func = std::bind(&Abstract::virtualFoo, this);
        func();
    }

protected:
    virtual void virtualFoo() = 0;
};


class Derived1 : public Abstract
{
private:
    void virtualFoo() override
    {
        std::cout << "I am Derived1\n";
    }
};

class Derived2 : public Abstract
{
private:
    void virtualFoo() override
    {
        std::cout << "I am Derived2\n";
    }
};


int main(int argc, char *argv[])
{
    Abstract * a1 = new Derived1;
    Abstract * a2 = new Derived2;

    a1->foo();
    a2->foo();

    return 0;
}

Цель вполне понятна, в функции базового класса foo () я хочу получить указатель на производные виртуальные функции.

Однако, насколько я понимаю, он не должен работать и даже не должен компилироваться с чисто виртуальной функцией. При использовании не чистой виртуальной функции она должна выполнять функцию базового класса. Но я был очень удивлен, увидев, что он компилируется и выдает намеченный результат: он печатает «I am Derived1», затем «I am Derived2»

Как &Abstract::virtualFoo может вернуть действительный указатель, даже не зная указателя на фактический объект, обязательный для доступа к vtable ???

Онлайн C ++ ссылка: https://onlinegdb.com/SJfku8rvV

Для меня действительный синтаксис должен быть:

        auto func = std::bind(&this->virtualFoo, this);

В качестве разыменования this должен фактически получить доступ к vtable и вернуть указатель на функцию. Но с ++ 11 так не думает.

1 Ответ

5 голосов
/ 12 марта 2019

Как &Abstract::virtualFoo может вернуть действительный указатель, даже не зная указателя на фактический объект, обязательный для доступа к vtable ???

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

Компилятор сохраняет необходимую информацию в указателе функции-члена, чтобы это произошло. Обратите внимание, что указатель на функцию-член не обязательно является просто указателем на один адрес. Он может содержать больше, чем это.

Точный способ, которым компилятор достигает этого, определяется реализацией.

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