Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/156.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 转换成员函数指针_C++_Pointers_Casting_Member Function Pointers_Reinterpret Cast - Fatal编程技术网

C++ 转换成员函数指针

C++ 转换成员函数指针,c++,pointers,casting,member-function-pointers,reinterpret-cast,C++,Pointers,Casting,Member Function Pointers,Reinterpret Cast,我需要使用一个成员函数指针,它接收在其他代码中使用的基类参数。好吧,我只想做下面的例子。这段代码运行得很好,但我想知道这样的强制转换是否总是安全的?我不能在这里进行动态或静态转换 #include <cstdio> class C { public:

我需要使用一个成员函数指针,它接收在其他代码中使用的基类参数。好吧,我只想做下面的例子。这段代码运行得很好,但我想知道这样的强制转换是否总是安全的?我不能在这里进行
动态
静态
转换

#include <cstdio>                                                   

class C
{                                                           
public:                                                             
        C () : c('c') {}                                            
        virtual ~C() {}                                             

        const char c;                                               
};                                                                  

class D : public C
{                                                
public:                                                             
        D () : d('d') {}                                            
        virtual ~D() {}                                             

        const char d;                                               
};                                                                  

class A 
{                                                           
public:                                                             
        A () {}                                                     
        virtual ~A() {}                                             

        void f( C& c ) { printf("%c\n",c.c); }                      
        void g( D& d ) { printf("%c %c\n",d.c,d.d); }               
};                                                                  

int main (int argc, char const* argv[])                             
{                                                                   
        void (A::*pf)( C& c ) = &A::f;                              
        void (A::*pg)( D& d ) = reinterpret_cast<void (A::*)(D&)>(&A::f);

        A a;                                                        
        C c;                                                        
        D d;                                                        

        (a.*pf)( c );                                               
        (a.*pg)( d );                                               

        return 0;                                                   
}                                                              
#包括
C类
{                                                           
公众:
C():C('C'){}
虚拟~C(){}
常量字符c;
};                                                                  
D类:公共C类
{                                                
公众:
D():D('D'){}
虚拟~D(){}
常量字符d;
};                                                                  
甲级
{                                                           
公众:
A(){}
虚拟~A(){}
void f(C&C){printf(“%C\n”,C.C);}
void g(D&D){printf(“%c%c\n”,D.c,D.D);}
};                                                                  
int main(int argc,char const*argv[]
{                                                                   
无效(A::*pf)(C&C)=&A:*f;
无效(A::*pg)(D&D)=重新解释铸件(&A::f);
A A;
C C;
D;
(a)pf(c);
(a.*pg)(d);
返回0;
}                                                              

您需要使用
重新解释演员表
使其正常工作。在这种情况下,它应该是安全的(请参见备注),但如果使用多重继承,它可能会失败,因为当将
D
作为
C
传递时,需要调整指针。编译器需要知道这必须发生,这在本例中是不可能的(使用
d
调用
pg
只会跳过这一步,成员函数将获得
d
对象的未修改地址)


备注:我说的是安全-实际上,它是未定义的行为,因为它将类型重新解释为一个不相关的类型并使用该类型,但它应该在大多数编译器上工作。请,请不要在生产代码中这样做。

编译器应该拒绝使用您编写的动态转换的代码。(我认为这是一个打字错误,考虑到你的介绍文字,你的意思是重新解释演员阵容)


使用reinterpret_cast,您不会遇到定义良好的情况(这主要涉及转换为另一种类型,然后再转换回原始类型)。因此,对于强制转换的结果,我们处于未指定的领域,对于调用强制转换的结果时的行为,我们处于未定义的领域。

否,您的示例不起作用。
首先,只能使用
dynamic\u cast
在相关类类型之间进行强制转换,而不能使用其他方法。
其次,即使您将
动态\u cast
替换为
重新解释\u cast
或C风格的cast(我认为您的意思),我也会得到以下输出:

c
c

不是你想要的

为什么它能工作并且不会可怕地崩溃,是因为在成员函数指针之间来回转换是“安全的”,不会丢失任何信息。
它仍然打印某些内容的原因是编译器没有发现类型错误,但程序集不关心类型,它只关心地址,因此它仍然会调用
A::f
,因为这是您保存的指针,而不管类型如何

有趣的是,即使您取消类的更新(
D
不从
C
继承),这仍然有效,这也是因为程序集不关心类型。按以下方式更改A中的功能:

void f( C& c ) { printf("f(C& c): %c\n",c.c); }
void g( D& d ) { printf("g(D& d): %c\n",d.d); }
导致以下输出:

f(C&C):C
f(C&C):d

“这是怎么回事?
D
甚至没有
c
成员!”。嗯,又是因为地址。两个变量与
指针的偏移量相同,即
+0
。现在让我们将另一个成员放入
C
(类简化):

然后再试一次,输出:

f(C&C):C
f(C&C):╠

是的,我们开始了
C::C
现在位于偏移量
+4
+0
+
sizeof int
),并且
printf
从那里读取。在
D
中,没有这样的偏移量,
printf
从未初始化的内存中读取。另一方面,访问未初始化的内存是未定义的行为


因此,最后得出结论:不,这不安全

>你试图做的事情不能在C++中合法地进行。C++不支持函数参数类型上的任何一种协方差或逆变,无论这是一个成员函数还是一个自由函数。 在您的情况下,实现它的正确方法是引入一个用于参数类型转换的中间函数

class A 
{                                                           
public:          
  ...                                                   
  void f( C& c ) { printf("%c\n",c.c); }                      
  void f_with_D( D& d ) { f(d); }
  ...
};          
让你的指针指向那个中间
class A 
{                                                           
public:          
  ...                                                   
  void f( C& c ) { printf("%c\n",c.c); }                      
  void f_with_D( D& d ) { f(d); }
  ...
};          
void (A::*pg)( D& d ) = &A::f_with_D;
A a;
D d;                                                        
(a.*pg)( d );
class A 
{                                                           
public:          
  ...                                                   
  void f( C& c ) { printf("%c\n",c.c); }                      
  void f( D& d ) { f(static_cast<C&>(d)); }
  ...
};