[英]Accessing private virtual functions within same class
我被问到,使用这段代码并且只写了extractMultAdd()
函数来返回variable.x
variable.y
variable.add()
和variable.multiply
。 我了解虚拟表的基本概念以及创建虚拟表的时间,但是尽管我尽了最大努力,但我不确定如何利用它们访问私有虚拟功能。 任何帮助,将不胜感激。
#include <cstdio>
#include <iostream>
class MultAdd
{
private:
int x;
int y;
virtual int add() //virtual fuction so vtable created for Thing class
{
return x+y;
}
virtual int multiply()
{
return x*y;
}
public:
MultAdd(){
x = 2;
y = 10;
}
};
int extractMultAdd(void* math)
{
return 0;
}
int main()
{
MultAdd variable;
printf("%d\n", extractMultAdd(&variable));
return 0;
}
我给您两个版本供您选择。 它们不遵循标准,并且绝对不是可移植的,但是在我测试时,它们都可以在MSVC 2013,GCC 4.9和clang 3.5上工作。 与第一个版本相比,第二个版本相对更安全,更便携。 实际上,我希望它相当强大。
版本1:
#include <iostream>
class MultAdd {
private:
int x;
int y;
virtual int add() { return x + y; }
virtual int multiply() { return x * y; }
public:
MultAdd() {
x = 2;
y = 10;
}
};
struct MultAddCracker: MultAdd {
int add();
int multiply();
};
void extractMultAdd(MultAdd& v) {
char* p = (char*)&v;
std::cout << *(int*)(p + sizeof(void*)) << '\n';
std::cout << *(int*)(p + sizeof(void*) + sizeof(int)) << '\n';
MultAddCracker* pcracker = (MultAddCracker*)&v;
std::cout << pcracker->add() << '\n';
std::cout << pcracker->multiply() << '\n';
}
int main() {
MultAdd v;
extractMultAdd(v);
}
版本2:
#include <iostream>
class MultAdd {
private:
int x;
int y;
virtual int add() { return x + y; }
virtual int multiply() { return x * y; }
public:
MultAdd() {
x = 2;
y = 10;
}
};
struct MultAddCracker {
int x;
int y;
virtual int add();
virtual int multiply();
};
void extractMultAdd(MultAdd& v) {
MultAddCracker& w = (MultAddCracker&)v;
std::cout << w.x << '\n';
std::cout << w.y << '\n';
std::cout << w.add() << '\n';
std::cout << w.multiply() << '\n';
}
int main() {
MultAdd v;
extractMultAdd(v);
}
好吧,如果您正在寻找一种可移植的方式,我可以提供C ++编译器必须支持的以下内容 。 这里将进一步讨论。 简而言之,它利用了以下事实:按照14.7.2p8,显式模板实例中会绕过访问检查规则:
14.7.2p8通常的访问检查规则不适用于用于指定显式实例化的名称。 [注:特别是,函数声明符中使用的模板参数和名称(包括参数类型,返回类型和异常规范)可能是私有类型或对象,通常无法访问这些对象,并且模板可能是成员模板或成员函数通常无法访问。]
它几乎可以完成您想做的事情; 唯一需要注意的是,模板声明不能在14.2的函数范围内:
模板声明只能作为名称空间或类范围声明出现
通过措辞的方式,这可能会破坏问题的实质。 我不知道将模板结构纳入函数范围的任何方法,但是如果有类似的技巧,则可以100%完成您想要的操作。
////////////////////////////////////////////////////////////////////////////////////////
//// The template classes can unfortunately not be declared inside extractMultAdd ()
////////////////////////////////////////////////////////////////////////////////////////
#define ROB_PRIVATE_MEMBER_INST(CLASS, TYPE, MEMBER) \
template<typename T> \
struct CLASS##_##MEMBER##_rob_tag { \
typedef T CLASS::*type; \
friend type get(CLASS##_##MEMBER##_rob_tag); \
}; \
template<typename Tag, typename Tag::type M> \
struct CLASS##_##MEMBER##_rob_private \
{ \
friend typename Tag::type get(Tag) { return M; } \
}; \
template struct CLASS##_##MEMBER##_rob_private< \
CLASS##_##MEMBER##_rob_tag<TYPE> , &CLASS::MEMBER>; \
#define ROB_PRIVATE_MEMBER_INST_FN(CLASS, TYPE, MEMBER) \
template<typename T> \
struct CLASS##_##MEMBER##_rob_tag { \
typedef T type; \
friend type get(CLASS##_##MEMBER##_rob_tag); \
}; \
template<typename Tag, typename Tag::type M> \
struct CLASS##_##MEMBER##_rob_private \
{ \
friend typename Tag::type get(Tag) { return M; } \
}; \
template struct CLASS##_##MEMBER##_rob_private< \
CLASS##_##MEMBER##_rob_tag<TYPE> , &CLASS::MEMBER>; \
#define ROB_PRIVATE_MEMBER_ACCESS(CLASS, INSTANCE, TYPE, MEMBER) \
(INSTANCE.*get(CLASS##_##MEMBER##_rob_tag<TYPE>())) \
////////////////////////////////////////////////////////////////////////////////////////
//// Actually use the macros
////////////////////////////////////////////////////////////////////////////////////////
ROB_PRIVATE_MEMBER_INST(MultAdd, int, x);
ROB_PRIVATE_MEMBER_INST(MultAdd, int, y);
ROB_PRIVATE_MEMBER_INST_FN(MultAdd, int(MultAdd::*)(), add);
ROB_PRIVATE_MEMBER_INST_FN(MultAdd, int(MultAdd::*)(), multiply);
////////////////////////////////////////////////////////////////////////////////////////
//ROB_PRIVATE_MEMBER_INST_FN(MultAdd, int(__thiscall *)(), add);
int extractMultAdd(void* math)
{
// No need to pass as void*
MultAdd *pMA(reinterpret_cast<MultAdd*>(math));
// ROB_PRIVATE_MEMBER_INST(MultAdd, int, x); // Note that unfortunately this isn't possible
// The 4 values, retrieved in a portable way
int robbed_x = ROB_PRIVATE_MEMBER_ACCESS(MultAdd, *pMA, int, x);
int robbed_y = ROB_PRIVATE_MEMBER_ACCESS(MultAdd, *pMA, int, y);
int robbed_add = ROB_PRIVATE_MEMBER_ACCESS(MultAdd, *pMA, int(MultAdd::*)(), add)(); // Note we're calling function with ()
int robbed_mul = ROB_PRIVATE_MEMBER_ACCESS(MultAdd, *pMA, int(MultAdd::*)(), multiply)(); // Note we're calling function with ()
return 0;
}
忽略朋友声明警告并滚动到输出:
当然,“仅在extractMultAdd()函数中编写”可能会为这种语义上的欺骗留出一些空间:
int extractMultAdd(void* math)
{
return extractMultAdd_impl(math);
}
// structs
int extractMultAdd_impl(void* math)
{
// original code ...
} // <== Original brace :)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.