На главную
ПРАВИЛА FAQ Помощь Участники Календарь Избранное DigiMania RSS
msm.ru
Модераторы: JoeUser, Qraizer, Hsilgos
  
> Вызов приватного метода базового класса из дочернего
Приветствую!

Как-то недавно где-то на форуме поднималась сабжевая тема. Захотелось поэксперементировать, вызвать напрямую, и таки получилось. Скажу сразу что реализация - есть хак. Иными словами, некоторые компиляторы могут собрать неработающий код. Вощем, опубликую чтобы было :lol:

Онлайн выполнение тут.

ExpandedWrap disabled
    #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;
    }
Мои программные ништякиhttp://majestio.info
Т.е. вызывался приватный метод?
Какая прелесть.
無駄に 5 分
Ой, делов-то:
ExpandedWrap disabled
    #define private public
    #include "BaseClass.h"

:D
Pacific, задача была вызвать приватный метод, а не делать его пабликом.
Мои программные ништякиhttp://majestio.info
На стековерфлове предложили еще один вариант:

ExpandedWrap disabled
    #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)();
    }
Мои программные ништякиhttp://majestio.info
DELETED

Сначала, не подумав, решил, что достаточно сделать
ExpandedWrap disabled
    static_cast<Base*>(this)
:D
Не, без тяжелых извращений к приватным членам класса доступ не получить. И не надо!
Сообщение отредактировано: Serpentus -
JoeUser, чему ты удивляешься-то? Тому, что при наличии указателя на что-то можно с чем-то делать всё, минуя любые охранные средства языка? Дык не составляет труда получить доступ и к приватным мемберам. Я даже как-то код писал, который в ран-тайм распарсивает структуру с битовыми полями и составляет словарь из битовых смещений от начала и длин каждого такого поля. Это требовалось для тестового движка одного из проектов.
Структура VMT не стандартизирована, даже её наличия не требуется. Твой код написан под конкретную 32-битную реализацию – кстати, какую? – и нет никаких гарантий, что будет работать в других. Код со СтэкОверфлоу не страдает этим недостатком, но страдает другим: он не должен компилиться.

Добавлено
Но я могу предложить другой способ.
ExpandedWrap disabled
    #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)();
    }
Одни с годами умнеют, другие становятся старше.
Цитата Qraizer @
Твой код написан под конкретную 32-битную реализацию – кстати, какую?

Это почему?

Цитата Qraizer @
Но я могу предложить другой способ.

"Легальные" способы, в случае перегрузки, вызовут перегруженный метод, а не базового класса. А в твоем варианте как с этим?
Мои программные ништякиhttp://majestio.info
Цитата Qraizer @
32-битную реализацию – кстати, какую?

Собирал на 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
Мои программные ништякиhttp://majestio.info
Цитата JoeUser @
Это почему?
Уже нет, uint32_t* заменил на void**.
Цитата JoeUser @
А в твоем варианте как с этим?
Мой строго стандартен.
Одни с годами умнеют, другие становятся старше.
2 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
1 пользователей: Алексей_Л


[ Script Execution time: 0,1191 ]   [ 20 queries used ]   [ Generated: 26.04.17, 15:42 GMT ]