#опытным
Оказывается способов легально залезть в непубличные кишки вашего класса довольно много, и сегодня обсудим еще один метод.
Мы уже с вами говорили про дружественные функции и что им дозволено получать доступ к приватным членами класса.
Но давайте посмотрим на следующий пример:
template <typename T>
struct Foo {
friend void bar() { cout << "Got it!" << endl; }
};
void bar();
template struct Foo<int>;
bar();
У нас есть шаблонная структура и у нее есть дружественная функция. Пока шаблон не инстанцирован, компилятор не видит определения функции. Поэтому чтобы вызвать
bar, нужно явно инстанцировать шаблон и объявить функцию во внешнем скоупе, чтобы компилятор мог найти ее по имени.Давайте проследим, что произошло. Функция bar - по сути свободная функция, которая может использовать все члены Foo. Но не только их. Она еще может использовать шаблонные параметры конкретной инстанциации.
И вот тут мы возвращаемся к тому, что использование имени приватного поля абсолютно законно в контексте явной инстанциации(см. предыдущий пост).
Давайте сделаем шаблонный параметр Foo указателем на поле и инстанцируем этот шаблон с указателем на приватное поле класса:
class Private {
private:
int data{};
};
template<int Private::* Member> // pointer to data member
struct Stealer {
friend int& dataGetter(Private& iObj) {
return iObj.*Member;
}
};
template struct Stealer<&Private::data>; // explicit instantiation
int& dataGetter(Private&);
int main() {
Private obj;
dataGetter(obj) = 42;
}Вот и все, получаем ссылку на приватное поле и крутим его, как хотим. Можно поиграться с примером тут.
И еще один из шаблоны сломали инкапсуляцию. Да что ж это такое!
Спасибо, @SoulslikeEnjoyer, за материалы для поста)
Exploit loopholes. Stay cool.
#cppcore #template #fun