有没有办法获得C ++虚拟成员函数地址 [英] Is there a way to get the C++ virtual member function address

查看:149
本文介绍了有没有办法获得C ++虚拟成员函数地址的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我搜索了这篇文章:
C ++:使用成员函数指针获取函数虚拟'地址'

为了测试虚拟成员函数是否通常位于对象的起始地址,我写了代码如下:

  #include< pwd.h> 
#include< string.h>
#include< stdio.h>

class Base
{
public:
int mBase1;
char mBase2;
virtual void foo()
{
fprintf(stderr,Base foo called \\\
);
}
};

class Child:public Base
{
public:
int cc;
virtual void foo()
{
fprintf(stderr,Child foo called);
}
};


int main(int argc,char * argv [])
{
Base bb;
fprintf(stderr,[mBase1%p] [mBase2%p] [foo%p] \\\
,& bb.mBase1,& bb.mBase2,& Base :: foo);
返回0;
}

编译时,我收到警告:

  test.cpp:30:88:警告'%p'需要类型为'void *'的参数,但参数5的类型为'void(Base :: * )()'[-Wformat] 

输出结果为:

  [mBase1 0xbfc2ca38] [mBase2 0xbfc2ca3c] [foo 0x1] 

我认为它是有线的。


  1. 是否有任何漂亮方法来获取成员函数(不是静态成员函数地址?)。除了下面的方法,还有其他的优雅方式吗?

      typedef void(Base :: * Foo)(); 
    Foo f =& Base :: foo();


  2. 为什么不是& Base :: foo 获取正确的C ++成员地址?

    解决方案


    为什么& Base :: foo没有得到正确的C ++成员地址?

    指向成员的指针是不同于指针的类型(实际上,它们比类型本身更多偏移量),特别是它们不能转换为 void * (他们可以在GCC上,但它可能是一个编译器扩展)。

    参见C ++ 11标准的第8.3.3 / 3节:


    指向成员的指针不应指向类的静态成员(9.4),具有引用类型的成员或cv void。
    [注:另见5.3和5.5。 指向成员的指针类型与指针类型不同,也就是说,指向成员的指针仅由指向成员声明符语法的指针声明,决不会由指针声明符语法声明。 C ++中没有引用成员类型。

    此外,第5.2.10 / 10段(约 reinterpret_cast<> )定义了指向成员的唯一可能转换,如下所示:

    lockquote

    类型指针指向X的成员如果T1和T2都是函数类型或两种对象类型,则可以将类型T1显式转换为不同类型的指针指向T2类型的Y成员的指针。空成员指针值(4.11)被转换为目标类型的空成员指针值。此转换的结果是未指定的,除了以下情况:

    - 将指针类型的prvalue转换为指向成员函数类型的不同指针,返回到它的原始类型产生原始指针到成员值。

    - 将类型为指针的类型的指针转换为类型为T1的X的数据成员为类型指针到T2类型的Y的数据成员(其中T2的对齐要求不比T1更严格),并返回到其原始类型产生原始指针到成员值。



    I searched this article: C++ : Getting function virtual 'address' with member function pointer

    In order to test if the virtual member function is usually at the beginning address of the object, I wrote the code as following:

    #include <pwd.h>
    #include <string.h>
    #include <stdio.h>
    
    class Base
    {
    public:
        int mBase1;
        char mBase2;
        virtual void foo()
        {
            fprintf(stderr,"Base foo called\n");
        }
    };
    
    class Child: public Base
    {
    public:
        int cc;
        virtual void foo()
        {
            fprintf(stderr,"Child foo called");
        }
    };
    
    
    int main(int argc, char *argv[])
    {
        Base bb;
        fprintf(stderr,"[mBase1 %p][mBase2 %p] [foo %p]\n",&bb.mBase1,&bb.mBase2,&Base::foo);
        return 0;
    }
    

    when compiling, I got a warning:

    test.cpp:30:88: warning ‘%p’ expects argument of type ‘void*’, but argument 5 has type ‘void (Base::*)()’ [-Wformat]
    

    The output is:

    [mBase1 0xbfc2ca38][mBase2 0xbfc2ca3c] [foo 0x1]
    

    I consider it's wired.

    1. Is there any "pretty method" to get the member function (not static member function address?). Besides the following method, is there any other elegant way?

      typedef void (Base::*Foo)();
      Foo f = &Base::foo();
      

    2. Why doesn't &Base::foo get the correct C++ member address?

    解决方案

    Why doesn't &Base::foo get the correct C++ member address?

    Pointers to member are different types than pointers (they are, in fact, more offsets than types themselves) and, in particular, they cannot be converted to void* (they can on GCC, but it's probably a compiler extension).

    See Paragraph 8.3.3/3 of the C++11 Standard:

    A pointer to member shall not point to** a static member of a class (9.4), a member with reference type, or "cv void." [ Note: See also 5.3 and 5.5. The type "pointer to member" is distinct from the type "pointer", that is, a pointer to member is declared only by the pointer to member declarator syntax, and never by the pointer declarator syntax. There is no "reference-to-member" type in C++. —end note ]

    Also, Paragraph 5.2.10/10 (about reinterpret_cast<>) defines the only possible conversions for pointers to member as follows:

    A prvalue of type "pointer to member of X of type T1" can be explicitly converted to a prvalue of a different type "pointer to member of Y of type T2" if T1 and T2 are both function types or both object types. The null member pointer value (4.11) is converted to the null member pointer value of the destination type. The result of this conversion is unspecified, except in the following cases:

    — converting a prvalue of type "pointer to member function" to a different pointer to member function type and back to its original type yields the original pointer to member value.

    — converting a prvalue of type "pointer to data member of X of type T1" to the type "pointer to data member of Y of type T2" (where the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer to member value.

    这篇关于有没有办法获得C ++虚拟成员函数地址的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆