Доступ к нестатическим методам класса в VC++ 2019

105
11 июня 2021, 22:20

Насколько "криминальным" является такой доступ к нестатическим методам класса? Делал в Visual studio 2019 Community, с дефолтными настройками. Переносимость на другие платформы не важна, важно, чтобы это работало в дальнейших версиях Visual C++

#include <iostream>
class Base {
public:
    int val;
    Base():val(0) {}
    virtual int Func1(int newval)
    {
        val = newval;
        return val;
    }
};
class Child : public Base{
public:
    virtual int Func2(int newval)
    {
        val = newval*newval;
        return val;
    }
    virtual int Func1(int newval)
    {
        val = newval * 2;
        return val;
    }
    Child() : Base() {}
};
class Child2 : public Child
{
private:
    virtual int Func2(int newval)
    {
        val = newval * newval * newval;
        return val;
    }
};

int main()
{
    Base base;
    Child child;
    Child2 child2;
    int (Base::*func)(int) = &Base::Func1;
    int (Base::*func2)(int) = reinterpret_cast<int (Base::*)(int)>(&Child::Func2);
    Base* t = &base;
    (t->*func)(3);
    std::cout << "base::val=" << base.val << "\n";
    t = &child;
    (t->*func)(3);
    std::cout << "child::val=" << child.val << "\n";
    (t->*func2)(3);
    std::cout << "child::val=" << child.val << "\n";
    t = &child2;
    (t->*func)(3);
    std::cout << "child2::val=" << child2.val << "\n";
    (t->*func2)(3);
    std::cout << "child2::val=" << child2.val << "\n";
    getchar();
}

Выводит следующее:

base::val=3
child::val=6
child::val=9
child2::val=6
child2::val=27

Пробовал и релиз и дебаг и х86 и х64 - везде результат одинаков, ошибок не выдается.

Answer 1

В вашем коде все было бы абсолютно легально, если бы не неуместное использование reinterpret_cast.

Это контравариантное преобразование типов (преобразование указателя на член класса в направлении от потомка к предку) поддерживается в С++. Но делается оно через static_cast

int (Base::*func2)(int) = static_cast<int (Base::*)(int)>(&Child::Func2);

Обратите внимание, что даже несмотря на то, что в классе Base нет метода Func2, это преобразование является полностью легальным и определенным. Язык С++ требует наличия соответствующего метода Func2 в динамическом типе объекта только в момент вызова через такой указатель. В момент выполнения преобразования и инициализации указателя таких требований не накладывается.

То есть если бы далее вдруг сделали

Base* t = &base;
(t->*func2)(3);  // UB

то вы бы наткнулись на неопределенное поведение при вызове. Но в вашем коде таких нарушений нет.

Из-за неуместного использования reinterpret_cast вместо static_cast ваш код имеет неопределенное поведение. В остальном никаких проблем в коде нет. Да, окончательное разрешение вызовов виртуальных методов класса через указатель в С++ делается в момент вызова. То есть все должно работать именно так, как оно работает в вашем примере.

Замените reinterpret_cast на static_cast и вы получите корректный код с полностью определенным спецификацией языка С++ поведением. Никакой "завязки на компилятор" в этом коде нет. Скорее наоборот, именно в VS для того, чтобы заставить аналогичный код корректно работать в более сложных случаях (множественное наследование, виртуальное наследование) вам придется повозиться с #pragma pointers_to_members. В других компиляторах все будет работать сразу.

READ ALSO
Мяч со временем теряет скорость

Мяч со временем теряет скорость

Есть мяч, который падаетУпав на землю, он отталкивается, но проблема в том, что после каждого отталкивания он поднимается на высоту меньше,...

107
Добавить в span &lt;i class&gt;&lt;/i&gt;

Добавить в span <i class></i>

Впервые столкнулся с тем, что нужно добавить в span еще и <i class></i>, как в этом примере: <span id="Department"><i class="glyphicon glyphicon-th-large btn-default"></i></span>...

91
Добавить атрибут через JS

Добавить атрибут через JS

Есть код который создаёт кнопку которая открывает проводник на гаджете пользователяСейчас мне понадобилось добавить к этой кнопке атрибут...

95
Onchange в jquery при условиях

Onchange в jquery при условиях

Подскажите неясности по onchange и условиям

119