Вызов частного метода в С++
Это чисто теоретический вопрос, я знаю, что если кто-то объявит метод 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