简体   繁体   English

访问同一类中的私有虚拟功能

[英]Accessing private virtual functions within same class

I was asked, using this code and only writing in the extractMultAdd() function, to return variable.x variable.y variable.add() and variable.multiply . 我被问到,使用这段代码并且只写了extractMultAdd()函数来返回variable.x variable.y variable.add()variable.multiply I understand that the basic concept of virtual tables and when they are created, but despite my best efforts, I'm not quite sure how to leverage them to access the private virtual functions. 我了解虚拟表的基本概念以及创建虚拟表的时间,但是尽管我尽了最大努力,但我不确定如何利用它们访问私有虚拟功能。 Any help would be appreciated. 任何帮助,将不胜感激。

#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;
}

I give you two versions to choose. 我给您两个版本供您选择。 They do not follow the standard, and are by no means portable, but both work on MSVC 2013, GCC 4.9, and clang 3.5 as I test it. 它们不遵循标准,并且绝对不是可移植的,但是在我测试时,它们都可以在MSVC 2013,GCC 4.9和clang 3.5上工作。 The second version is relatively safer and more portable than the first one. 与第一个版本相比,第二个版本相对更安全,更便携。 In fact, I expect it to be rather robust. 实际上,我希望它相当强大。

Version 1: 版本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);
}

Version 2: 版本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);
}

Well, if you're looking for a portable way, I could offer the following, which a C++ compiler must support . 好吧,如果您正在寻找一种可移植的方式,我可以提供C ++编译器必须支持的以下内容 It is discussed further here . 这里将进一步讨论。 In short, it leverages the fact that access checking rules are bypassed in explicit template instantiations as per 14.7.2p8: 简而言之,它利用了以下事实:按照14.7.2p8,显式模板实例中会绕过访问检查规则:

14.7.2p8 The usual access checking rules do not apply to names used to specify explicit instantiations. 14.7.2p8通常的访问检查规则不适用于用于指定显式实例化的名称。 [Note: In particular, the template arguments and names used in the function declarator (including parameter types, return types and exception specifications) may be private types or objects which would normally not be accessible and the template may be a member template or member function which would not normally be accessible.] [注:特别是,函数声明符中使用的模板参数和名称(包括参数类型,返回类型和异常规范)可能是私有类型或对象,通常无法访问这些对象,并且模板可能是成员模板或成员函数通常无法访问。]

It does almost what you want to do; 几乎可以完成您想做的事情; the only caveat with this is that template declarations cannot be at the function scope as per 14.2: 唯一需要注意的是,模板声明不能在14.2的函数范围内:

A template declaration can appear only as a namespace or class scope declaration 模板声明只能作为名称空间或类范围声明出现

This might break the spirit of the question though the way it is phrased. 通过措辞的方式,这可能会破坏问题的实质。 I don't know of any way to weasle the template structs into the function scope, but if there is a similar trick, this could do 100% what you want. 我不知道将模板结构纳入函数范围的任何方法,但是如果有类似的技巧,则可以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;
}

Ignore the friend declaration warnings and scroll to output: 忽略朋友声明警告并滚动到输出:

Run example 运行示例

Of course "only writing in the extractMultAdd() function" might leave some room for this semantic trickery: 当然,“仅在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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM