На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: 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;
      }
      Т.е. вызывался приватный метод?
      Какая прелесть.
        Ой, делов-то:
        ExpandedWrap disabled
          #define private public
          #include "BaseClass.h"

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

            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)();
              }
              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 @
                  Но я могу предложить другой способ.

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


                      Рейтинг@Mail.ru
                      [ Script execution time: 0,0404 ]   [ 17 queries used ]   [ Generated: 29.03.24, 01:30 GMT ]