Вызов частного метода в С++

Это чисто теоретический вопрос, я знаю, что если кто-то объявит метод private, вы, вероятно, не должны его называть. Мне удалось вызвать частные виртуальные методы и изменить частные члены для экземпляров, но я не могу понять, как вызвать частный не виртуальный метод (без использования __asm). Есть ли способ получить указатель на метод? Есть ли другие способы сделать это?

EDIT: я не хочу менять определение класса! Мне просто нужен хак/обходной путь.:)

Ответы

Ответ 1

#include заголовочный файл, но:

#define private public
#define class struct

Понятно, что вам нужно обойти различные охранники и т.д. и сделать это в изолированном блоке компиляции.

EDIT: Все еще хакерский, но в меньшей степени:

#include <iostream>

#define private friend class Hack; private

class Foo
{
public:
    Foo(int v) : test_(v) {}
private:
    void bar();
    int test_;
};
#undef private
void Foo::bar() { std::cout << "hello: " << test_ << std::endl; }

class Hack
{
public:
    static void bar(Foo& f) {
        f.bar();
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    Foo f(42);
    Hack::bar(f);
    system("pause");
    return 0;
}

Ответ 2

Смотрите мой пост в блоге. Я переписываю код здесь

template<typename Tag>
struct result {
  /* export it ... */
  typedef typename Tag::type type;
  static type ptr;
};

template<typename Tag>
typename result<Tag>::type result<Tag>::ptr;

template<typename Tag, typename Tag::type p>
struct rob : result<Tag> {
  /* fill it ... */
  struct filler {
    filler() { result<Tag>::ptr = p; }
  };
  static filler filler_obj;
};

template<typename Tag, typename Tag::type p>
typename rob<Tag, p>::filler rob<Tag, p>::filler_obj;

Некоторые классы с частными членами

struct A {
private:
  void f() {
    std::cout << "proof!" << std::endl;
  }
};

И как получить к ним доступ

struct Af { typedef void(A::*type)(); };
template class rob<Af, &A::f>;

int main() {
  A a;
  (a.*result<Af>::ptr)();
}

Ответ 3

Он может вызываться, если функция public возвращает адрес функции private, тогда любой может использовать этот адрес для вызова частной функции.

Пример

class A
{
   void f() { cout << "private function gets called" << endl; }
 public:
     typedef void (A::*pF)();
     pF get() { return &A::f; }
};

int main() 
{
        A a;
        void (A::*pF)() = a.get();
        (a.*pF)(); //it invokes the private function!
}

Вывод:

private function gets called

Демо на идеоне: http://www.ideone.com/zkAw3

Ответ 4

Вызвать частный метод из общедоступной функции того же класса.

Ответ 5

У вас friend классы и функции.

Я знаю, что если кто-то объявит метод приватным, вы, вероятно, не следует называть его.

Точка не "вы не должны ее называть", это просто "вы не можете ее назвать". Что ты пытаешься сделать?

Ответ 6

Самый простой способ:

#define private public
#define protected public

Ответ 7

Последующий отчет по T.E.D. Ответ: Не редактируйте заголовок. Вместо этого создайте свою личную копию заголовка и вставьте некоторые объявления friend в эту фиктивную копию заголовка. В вашем источнике #include этот фиктивный заголовок, а не реальный. Вуаля!

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

Добавление
Этот подход не будет работать, если заголовок, о котором идет речь, использует #pragma once вместо защиты #include, чтобы гарантировать, что заголовок является идемпотентным.

Ответ 8

Ну, очевидным способом было бы отредактировать код, чтобы он больше не был приватным.

Если вы настаиваете на том, чтобы найти злой способ сделать это... ну... с некоторыми компиляторами он может работать, создайте собственную версию файла заголовка, где этот метод public вместо private. У зла есть противный способ отскока на вас, хотя (вот почему мы называем это "злом" ).

Ответ 9

Я думаю, что ближе всего к хакеру относится это, но это не просто неразумное, а undefined поведение, поэтому у него нет семантики. Если это происходит, чтобы функционировать так, как вы хотите, для какого-либо одного вызова программы, то этот чистый шанс.

Ответ 10

Определите аналогичный класс, который является тем же, что и общедоступная функция.

Затем создайте объект с частной функцией с помощью функции public, затем вы можете вызвать публичную функцию.

Ответ 11

Если мы говорим о MSVC, я думаю, что самый простой способ без другого вреда, чем сам вызов частного метода, - это большой __asm:

class A
{
private:
    void TestA () {};
};

A a;
__asm
{
    // MSVC assumes (this) to be in the ecx.
    // We cannot use mov since (a) is located on the stack
    // (i.e. [ebp + ...] or [esp - ...])
    lea     ecx, [a]
    call    A::TestA
}

Ответ 12

Для GCC это можно сделать, используя искаженное имя функции.

#include <stdio.h>

class A {
public:
    A() {
        f(); //the function should be used somewhere to force gcc to generate it
    }
private:
    void f() { printf("\nf"); }
};

typedef void(A::*TF)();

union U {
    TF f;
    size_t i;
};

int main(/*int argc, char *argv[]*/) {
    A a;
    //a.f(); //error
    U u;
    //u.f = &A::f; //error

    //load effective address of the function
    asm("lea %0, _ZN1A1fEv"
    : "=r" (u.i));
    (a.*u.f)();
    return 0;
}

Mangled names можно найти в файлах nm *.o.

Добавить -masm = опция компилятора Intel

Источники: Ошибка GCC: нельзя применять offsetof для функции-члена MyClass:: MyFunction https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html