【问题标题】:Access a private virtual member-function through pointers通过指针访问私有虚拟成员函数
【发布时间】:2016-05-04 00:25:02
【问题描述】:
class foo{
   public:
   int n;
   private:
   virtual void sayHi(){
      cout<<"Hi there!";
   }

};

如何获取sayHi()的地址??

main(){
foo f;
typedef void(*fptr)();
fptr func = reinterpret_cast<fptr>((&f)[0]);
(*func)();
}

上面的代码不起作用。

我知道“f”对象的前 8 个字节是指向虚拟表的指针,其中包含指向函数的指针,我使用的是 64 位机器。我基本上是试图通过它的指针调用 sayHi(),而不是直接从 f 调用它,因为 sayHi() 无论如何都是私有的!我该怎么做?我分配对了吗?

【问题讨论】:

  • @Noor Thabit: 呃...在“标准 C++”中无法做到这样。标准 C++ 甚至没有“虚拟表”的概念。
  • 您确定您不是在寻找pointer to member
  • @NoorThabit:作为一个成员函数,你不能不通过指针“直接调用它”。它有一个隐含的“this”参数,至少需要一个值(尽管您可以将它传递给nullptr)。但正如 immibis 所说,作为成员,您需要一个指向成员的指针。
  • @RyanHaining 不加好友,功能是私有的!
  • @NoorThabit 那么你将不得不使用我在上一条评论中链接的那个模板 runaround。不过,您在这里的问题的标题与您实际提出的问题完全不同。

标签: c++ pointers casting virtual-functions


【解决方案1】:

您不能简单地拥有一个指向非静态成员函数的指针并在没有对象的情况下调用它。解释您的问题的最直接的方法是使用pointer-to-member,如下所示:

auto fptr = &foo::sayHi;
foo f;
(f.*fptr)();

现在,你说你想调用它而不必通过f。目前尚不清楚这究竟意味着什么。使用 lambda 可能足以创建一个可按您想要的方式工作的可调用对象

auto func = [] { return foo{}.sayHi(); };
func(); // call

或使用特定对象并通过引用(显示)或按值捕获它

foo f;
auto func = [&f] { return f.sayHi(); };
func();

【讨论】:

  • @NoorThabit:为什么不呢?
  • 可能是因为sayHi 是私有的! @MooingDuck
【解决方案2】:

sayHi() 是类的非静态方法。您需要使用 pointer-to-method 而不是原始指针(方法指针的实现是特定于编译器的,因此假设指向方法的指针的内部布局不可移植) .

另外,sayHi()foo私有,所以main() 不能直接访问它。您需要:

  1. sayHi() 声明为公开

    class foo
    {
       int n;
    public:
       virtual void sayHi(){
          cout << "Hi there!";
       }
    };
    
    int main()
    {
        typedef void (foo::*fptr)();
        fptr func = &foo::sayHi;
        foo f;
        (f.*func)();
        return 0;
    }
    
  2. 使main() 成为friendfoo

    class foo
    {
       int n;
       virtual void sayHi(){
          cout << "Hi there!";
       }
       friend int main();
    };
    
    int main()
    {
        typedef void (foo::*fptr)();
        fptr func = &foo::sayHi;
        foo f;
        (f.*func)();
        return 0;
    }
    

【讨论】:

  • 感谢您的努力。但是 sayHi() 是私有的!
  • @EissaN.: 如果sayHi() 被声明为public,或者如果main() 被声明为friendfoo,则代码对我来说编译得很好,否则@ 987654336@无法访问。
【解决方案3】:

好吧,ISO C++ 禁止使用绑定成员函数的地址来形成指向成员函数的指针。但是,如果有帮助,您可以执行类似的操作。您可以查看结果here

#include <iostream>
using namespace std;

class foo{
   int n;
public:
   virtual void sayHi(){
      cout<<"Hi there!";
   }
};

typedef void(*fptr)();

int main() {
    auto func = reinterpret_cast<fptr>(&foo::sayHi);
    (*func)();
    return 0;
}

【讨论】:

  • 这不是可移植代码,不太可能在运行时工作。您正在将指向方法的指针分配给原始指针,使用类型转换来防止编译器抱怨潜在的非法和危险的事情。而且您仍然不能使用原始指针调用非静态类方法,调用堆栈将无法正确设置。
  • 感谢您的评论!您的解决方案有效!但是,函数必须是私有的!
猜你喜欢
  • 2015-12-17
  • 1970-01-01
  • 1970-01-01
  • 2015-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多