Объявление функции extern означает, что ее определение будет разрешено во время связывания, а не во время компиляции.
В отличие от обычных функций, которые не объявлены extern, его можно определить в любом из источников (но не в нескольких исходных файлах, иначе вы получите сообщение об ошибке компоновщика, говорящее, что вы указали несколько определений функции), в том числе тот, в котором он объявлен extern.So, в ур случае компоновщик разрешает определение функции в тот же файл.
Я не думаю, что это было бы очень полезно, но такие эксперименты дают лучшее представление о том, как работает компилятор и компоновщик языка.
Если класс содержит какие-либо шаблонные функции членства, можно специализировать ту функцию членства для удовлетворения потребностям. Даже если исходный разработчик не думал о нем.
safe.h
class safe
{
int money;
public:
safe()
: money(1000000)
{
}
template <typename T>
void backdoor()
{
// Do some stuff.
}
};
main.cpp:
#include <safe.h>
#include <iostream>
class key;
template <>
void safe::backdoor<key>()
{
// My specialization.
money -= 100000;
std::cout << money << "\n";
}
int main()
{
safe s;
s.backdoor<key>();
s.backdoor<key>();
}
Вывод:
900000
800000
Всем людям, предлагающим" #define частная общественность ":
Такого рода вещь недопустима . Стандарт запрещает defining/undef-ing макросы, которые лексически эквивалентны зарезервированным ключевым словам языка. В то время как Ваш компилятор, вероятно, не будет жаловаться (я должен все же видеть компилятор, который делает), это не что-то, что это - "Хорошая Вещь", чтобы сделать.
Около #define частная общественность Вы можете также #define частный защищенный и затем определять некоторый класс нечто как потомка требуемого класса для имения доступа к, он (теперь защищен) методы через преобразование типа.
просто создайте свою собственную функцию членства доступа для расширения класса.
Если Вы знаете, как Ваш компилятор C++ искажает имена, да.
, Если, я не предполагаю, это - виртуальная функция. Но тогда, если Вы знаете, как Ваш компилятор C++ создает VTABLE...
Редактирование: смотря на другие ответы, я понимаю, что неправильно читал вопрос и думал, что это было о функциях членства, не членских данных. Однако точка все еще стоит: если Вы знаете, как Ваш компилятор размечает данные, то можно получить доступ к тем данным.
Это на самом деле довольно легко:
class jail {
int inmate;
public:
int& escape() { return inmate; }
};
Если можно получить указатель на члена класса, можно использовать указатель, неважно, что спецификаторы доступа (даже методы).
class X;
typedef void (X::*METHOD)(int);
class X
{
private:
void test(int) {}
public:
METHOD getMethod() { return &X::test;}
};
int main()
{
X x;
METHOD m = x.getMethod();
X y;
(y.*m)(5);
}
, Конечно, мой любимый небольшой взлом является другом шаблонный черный ход.
class Z
{
public:
template<typename X>
void backDoor(X const& p);
private:
int x;
int y;
};
Принятие создателя вышеупомянутого определило бэкдор для его нормальной эксплуатации. Но Вы хотите получить доступ к объекту и посмотреть на переменные члена парламента, не занимающего официального поста. Даже если вышеупомянутый класс был скомпилирован в статическую библиотеку, можно добавить собственную шаблонную специализацию для бэкдора и таким образом получить доступ к участникам.
namespace
{
// Make this inside an anonymous namespace so
// that it does not clash with any real types.
class Y{};
}
// Now do a template specialization for the method.
template<>
void Z::backDoor<Y>(Y const& p)
{
// I now have access to the private members of Z
}
int main()
{
Z z; // Your object Z
// Use the Y object to carry the payload into the method.
z.backDoor(Y());
}
class A
{
int a;
}
class B
{
public:
int b;
}
union
{
A a;
B b;
};
, Который должен сделать это.
ЭТА: Это будет работать на этот вид тривиального класса, но как общая вещь это не будет.
TC ++ МН Раздел C.8.3: "Класс с конструктором, деструктором или операцией копии не может быть типом члена профсоюза..., потому что компилятор не знал бы который участник уничтожить".
, Таким образом, нас оставляют с лучшим выбором быть, чтобы объявить class B
соответствовать A
расположение и взлом для рассмотрения причинного места класса.
Hmmm, не знайте, работало ли это, но могло бы стоить попытки. Создайте другой класс с тем же расположением как объект с членами парламента, не занимающими официального поста, но с частным, измененным на общественность. Создайте переменную указателя на этот класс. Используйте простой бросок, чтобы указать на это на Ваш объект с членами парламента, не занимающими официального поста и попытаться вызвать закрытую функцию.
Ожидают искры и возможно катастрофический отказ;)
Определенно возможно получить доступ к членам парламента, не занимающим официального поста со смещением указателя в C++. Позволяет предполагают, что у меня было следующее определение типа, к которому я хотел получить доступ.
class Bar {
SomeOtherType _m1;
int _m2;
};
Принятие там не является никакими виртуальными методами в Панели, легкий случай является _m1. Участники в C++ хранятся как смещения ячейки памяти объекта. Первый объект при смещении 0, втором объекте при смещении sizeof (первый участник), и т.д.
, Таким образом, вот способ получить доступ к _m1.
SomeOtherType& GetM1(Bar* pBar) {
return*(reinterpret_cast<SomeOtherType*>(pBar));
}
Теперь _m2 является немного более трудным. Мы должны переместить исходный указатель sizeof (SomeOtherType) байты из оригинала. Бросок для обугливания должен гарантировать, что я увеличиваю в байтовом смещении
int& GetM2(Bar* pBar) {
char* p = reinterpret_cast<char*>(pBar);
p += sizeof(SomeOtherType);
return *(reinterpret_cast<int*>(p));
}
Следующее является подлым, недопустимым, зависимым от компилятора, и не может работать в зависимости от различных деталей реализации.
#define private public
#define class struct
, Но это - ответ на Ваш OP, в котором Вы явно приглашаете технику, которую, и я заключаю в кавычки, "полностью глупо и что любой, кто хотел бы попробовать такую вещь в производственном коде, должен быть уволен и/или застрелен".
<час>Другая техника должна получить доступ к данным члена парламента, не занимающего официального поста путем построения указателей с помощью hard-coded/hand-coded смещения с начала объекта.
поскольку у вас есть объект требуемого класса, я предполагаю, что у вас есть объявление класса. Теперь вы можете объявить другой класс с такими же членами, но оставить все спецификаторы доступа общедоступными.
Например, предыдущий класс:
class Iamcompprivate
{
private:
Type1 privateelement1;
Typ2 privateelement2;
...
public:
somefunctions
}
вы можете объявить класс как
class NowIampublic
{
**public:**
Type1 privateelement1;
Type2 privateelement2;
...
somefunctions
};
Теперь все, что вам нужно сделать, это преобразовать указатель класса Iamcompprivate
в указатель класса NowIampublic
] и используйте их по своему усмотрению.
Пример:
NowIampublic * changetopublic(Iamcompprivate *A)
{
NowIampublic * B = (NowIampublic *)A;
return B;
}
Я добавил запись в свой блог (см. ниже), которая показывает, как это можно сделать. Вот пример использования этого для следующего класса
struct A {
private:
int member;
};
Просто объявите для него struct, где вы его описываете, и инстанцируйте класс реализации, используемый для ограбления
// tag used to access A::member
struct A_member {
typedef int A::*type;
friend type get(A_member);
};
template struct Rob<A_member, &A::member>;
int main() {
A a;
a.*get(A_member()) = 42; // write 42 to it
std::cout << "proof: " << a.*get(A_member()) << std::endl;
}
Шаблон класса Rob
определен таким образом, и его нужно определить только один раз, независимо от того, к скольким приватным членам вы планируете получить доступ
template<typename Tag, typename Tag::type M>
struct Rob {
friend typename Tag::type get(Tag) {
return M;
}
};
Однако это не показывает, что правила доступа в c++ ненадежны. Правила языка предназначены для защиты от случайных ошибок - если вы попытаетесь похитить данные объекта, язык по замыслу не предпримет длинных путей, чтобы помешать вам.