【问题标题】:C++ Access Private Function Via Pointers [duplicate]C ++通过指针访问私有函数[重复]
【发布时间】:2015-04-26 17:47:04
【问题描述】:

假设我有以下内容:

class A {
private:
    int a;
    virtual int f() {return a;}
public:
    A(int t) {a = t;}
};

现在,如果我获得了指向 A 对象的指针,我该如何访问 int A::f()?我知道怎么弄!

void main () {
    A* x = new A(5);
    cout << ((int*)x)[2]; // returns 5;
}

但现在确定如何运行 A::f()。

更新:我知道这不是一个好的设计,并且应该隐藏私人。问题只是要知道类在编译器中是如何放入内存中的。

【问题讨论】:

  • 您要解决什么问题? hacky 解决方案将由实现定义 - 找到 vtable 指针,然后找到正确的表条目。

标签: c++ class pointers vtable


【解决方案1】:

我知道如何获取a

A* x = new A(5);
cout << ((int*)x)[2]; // returns 5;

这真是一个黑客!几乎与它一样不可移植,此代码会导致未定义的行为,而这种行为恰好会产生您期望的结果。这并不意味着它会在另一个系统上产生相同的结果,甚至当编译器选择不同的实现类时,甚至在同一个系统上也会产生相同的结果。

没有办法访问私有函数,除非有人给你一个指向引用它的成员函数的指针,或者将你的函数声明为friend

class A;
typedef  int (A::*FPTR)();
class A {
private:
    int a;
    virtual int f() {return a;}
public:
    A(int t) {a = t;}
    FPTR get_private() { return &A::f; }
};
int main() {
    A a(123);
    FPTR fp = a.get_private();
    int res = (a.*fp)();
    cout << res << endl;
    return 0;
}

Demo.

【讨论】:

    【解决方案2】:

    再次哼哼。类的私有部分是私有的。这意味着,只能由该类的方法访问,而不能由其他方法访问。

    如果你想打破这个,你肯定可以,但是你也打破了他想要呈现的接口的实现者想法......

    【讨论】:

    • 也许你应该考虑一下,例如,单元测试,有时访问私有部分是至关重要的,但我认为你总是按照书本行事
    • 对于单元测试,其公认的做法是有一个好朋友,例如Fixture-class 或其他取决于您使用的框架。
    【解决方案3】:

    数据技巧

    您的技巧是基于对对象内存布局的假设。幸运的是,对于您的特定示例,使用您的编译器,它似乎可以工作。

    如果我用 MSVC2013 编译这段代码,它根本不起作用!!如果我在构造函数中添加一些提示,我最终会发现当我使用 short 数组而不是 int 时它可以工作:

    A(int t) { a = t; cout << "A: " << (void*)this << " a: " << (void*)&a << " rel:" << (char*)&a - (char*)this << endl; }
    

    结论:一般来说,你不能依赖这个(在更复杂的例子中,你的编译器甚至不能)。标准给出了很limited ensurance about relative memory addresses of members

    第 9.2/15 节:(非联合)类的非静态数据成员 分配相同的访问控制,以便后面的成员拥有更高的权限 类对象中的地址。非静态数据的分配顺序 未指定具有不同访问控制的成员。执行 对齐要求可能会导致两个相邻的成员不 立即分配; (...)

    此外,您的技巧可能会创建pointer aliasing。因此,编译器会假设您的指针和对象的成员可能无效,从而导致生成的优化失败。

    函数技巧

    对于你的函数的地址,情况更糟。这同样没有在标准中定义,并且是特定于实现的。

    虚函数的常用实现是基于类特定的vtables。每个多态对象在类的某个地方都有一个指向其 vtable 的指针(通常在对象的前几个字节中。

    函数指针在vtable中的相对位置取决于该类的所有虚函数和所有继承的类。对于您的示例,使用 MSVC2013 我可以设法调用该函数:

    typedef int (A::*fptr)();
    fptr pf = (*(fptr**)x)[0];  // first unction in vtable
    (x->*pf)();  // call it. 
    

    但这当然是完全不标准的,而且非常危险!

    请记住,对于非虚函数,您根本无法从对象中获取地址。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-09-22
      • 1970-01-01
      • 2016-06-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-30
      • 2021-07-11
      相关资源
      最近更新 更多