Насколько "криминальным" является такой доступ к нестатическим методам класса? Делал в 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 - везде результат одинаков, ошибок не выдается.
В вашем коде все было бы абсолютно легально, если бы не неуместное использование 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
. В других компиляторах все будет работать сразу.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Есть мяч, который падаетУпав на землю, он отталкивается, но проблема в том, что после каждого отталкивания он поднимается на высоту меньше,...
Впервые столкнулся с тем, что нужно добавить в span еще и <i class></i>, как в этом примере: <span id="Department"><i class="glyphicon glyphicon-th-large btn-default"></i></span>...
Есть код который создаёт кнопку которая открывает проводник на гаджете пользователяСейчас мне понадобилось добавить к этой кнопке атрибут...