Версия для печати
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум на Исходниках.RU > C/C++: Общие вопросы > Вызов приватного метода базового класса из дочернего |
Автор: JoeUser 20.04.17, 23:36 |
Приветствую! Как-то недавно где-то на форуме поднималась сабжевая тема. Захотелось поэксперементировать, вызвать напрямую, и таки получилось. Скажу сразу что реализация - есть хак. Иными словами, некоторые компиляторы могут собрать неработающий код. Вощем, опубликую чтобы было Онлайн выполнение тут. <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> #include <iostream> // ----------------------------------------- class Base { public: virtual ~Base(){} private: virtual void ShowBase() { std::cout << "BaseShow" << std::endl; } }; // ----------------------------------------- class Derived: public Base { public: virtual void ShowDerived() { std::cout << "DerivedShow" << std::endl; } }; // ----------------------------------------- #ifdef _MSC_VER #define IDX 1 #else #define IDX 2 #endif int main() { Derived *D = new Derived(); (*(void(*)(void*))((void**)(*(void**)D))[IDX])(D); delete D; return 0; } |
Автор: simsergey 21.04.17, 05:01 |
Т.е. вызывался приватный метод? Какая прелесть. |
Автор: Pacific 21.04.17, 05:36 |
Ой, делов-то: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> #define private public #include "BaseClass.h" |
Автор: JoeUser 21.04.17, 06:19 |
Pacific, задача была вызвать приватный метод, а не делать его пабликом. |
Автор: JoeUser 21.04.17, 07:39 |
На стековерфлове предложили еще один вариант: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> #include <iostream> class Private { void private_func() { std::cout << "Pwned!" << std::endl; } }; class DerivedPrivate : public Private { }; using PTR = void (Private::*)(); PTR ptr; template <PTR ptr> struct Exploit { static struct D { D() { ::ptr = ptr; } } d; }; template <PTR ptr> typename Exploit<ptr>::D Exploit<ptr>::d; template struct Exploit<&DerivedPrivate::private_func>; int main() { (DerivedPrivate().*ptr)(); } |
Автор: Serpentus 21.04.17, 08:49 |
DELETED Сначала, не подумав, решил, что достаточно сделать <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> static_cast<Base*>(this) Не, без тяжелых извращений к приватным членам класса доступ не получить. И не надо! |
Автор: Qraizer 21.04.17, 12:31 |
JoeUser, чему ты удивляешься-то? Тому, что при наличии указателя на что-то можно с чем-то делать всё, минуя любые охранные средства языка? Дык не составляет труда получить доступ и к приватным мемберам. Я даже как-то код писал, который в ран-тайм распарсивает структуру с битовыми полями и составляет словарь из битовых смещений от начала и длин каждого такого поля. Это требовалось для тестового движка одного из проектов. Структура VMT не стандартизирована, даже её наличия не требуется. Твой код написан под конкретную 32-битную реализацию – кстати, какую? – и нет никаких гарантий, что будет работать в других. Код со СтэкОверфлоу не страдает этим недостатком, но страдает другим: он не должен компилиться. Добавлено Но я могу предложить другой способ. <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> #include <iostream> class Private { void private_func() { std::cout << "Pwned!" << std::endl; } public: template <typename T> void f(); }; /* ... */ class X {}; void (Private::*ptr)(); template <> void Private::f<X>() { ptr = &Private::private_func; } int main() { Private().f<X>(); (Private().*ptr)(); } |
Автор: JoeUser 21.04.17, 13:03 |
Это почему? "Легальные" способы, в случае перегрузки, вызовут перегруженный метод, а не базового класса. А в твоем варианте как с этим? |
Автор: JoeUser 21.04.17, 13:13 |
Собирал на FreeBSD 11.0 x64 - полет нормальный. Цитата uname -a FreeBSD freebsd-11.0 11.0-RELEASE-p1 FreeBSD 11.0-RELEASE-p1 #1: Tue Oct 11 13:50:48 MSK 2016 majestio@freebsd-11.0:/usr/obj/usr/src/sys/MYKERNEL amd64 |
Автор: Qraizer 21.04.17, 13:16 |
Уже нет, uint32_t* заменил на void**.Мой строго стандартен. |