将指向派生类中的成员函数的指针转换为指向抽象成员函数的指针

gle*_*ell 1 c++ inheritance pointer-to-member

我正在尝试做一些看起来应该相当常见的事情,但我找不到任何人讨论它。 stackoverflow 上的这篇文章与我想要做的类似,但不完全相同。

我有一个抽象基类:

#ifndef _ABASECLASS_H_
#define _ABASECLASS_H_

using namespace std;

#include <iostream>

#define CALL_MBR_FUNC(object, ptr_to_mem_func) ((object).*(ptr_to_mem_func))

class aBaseClass
{
public:

  typedef void (aBaseClass::*aBaseClass_mem_func)();

  int A;
  int B;

  aBaseClass();

  aBaseClass(int a, int b);

  virtual void function1(aBaseClass_mem_func infunc) = 0; 

  virtual void function2() = 0; 

};

#endif /* _ACLASS_H_ */
Run Code Online (Sandbox Code Playgroud)

我有一个派生类:

#ifndef _ASUBCLASS_H_
#define _ASUBCLASS_H_

using namespace std;

#include <iostream>
#include "aBaseClass.h"


/* A simple class containing two ints and some functions to demonstrate passing via various methods.  It is a subclass of aClass*/
class aSubClass: public aBaseClass
{
public:

  aSubClass();

  aSubClass(int a, int b);

  void function1(aBaseClass_mem_func infunc); 

  void function2(void); 

};

#endif /* _ASUBCLASS_H_ */
Run Code Online (Sandbox Code Playgroud)

其中函数 1 和函数 2 是:

void aSubClass::function1(aBaseClass_mem_func infunc) 
{
  CALL_MBR_FUNC(*this, infunc)();
}


void aSubClass::function2(void) 
{
  A = 42;
  B = 66;
}
Run Code Online (Sandbox Code Playgroud)

最后,在main()我尝试调用function1针对类型的对象aSubClass,将指针传递给function2in aSubClass

int main (int argc, const char * argv[])
{
  aSubClass eh(2,5);
// This doesn't work    
  aBaseClass_mem_func trythis = &aSubClass::function2;
// This also doesn't work
  eh.function1(&aSubClass::function2);

  return(0);
}
Run Code Online (Sandbox Code Playgroud)

好的,我们可以自动将派生指针类型转换为基类型指针。我现在读到我们无法将指向派生成员函数的指针传递给指向基类成员函数的指针。我想我明白为什么(派生成员函数可能会利用派生类中存在但基类中不存在的东西)。

但我正在尝试构建一个包含两类类(派生自两个基类)的库。将它们称为基类 1 和基类 2。基类 1 的任何派生类中的成员函数之一需要能够从基类 2 的任何派生类中传递特定的成员函数。我可以使用一些技巧来进行必要的演员阵容吗?我是否必须使用explicit关键字并以某种方式定义强制转换?

Bar*_*rry 5

你可以大大缩短这个例子:

struct B {
    virtual void foo() = 0;
};

struct D : B {
    void foo() override { }
};

int main() {
    void (B::*ptr)() = &D::foo; // error: cannot initialize a variable of
                                // type 'void (B::*)()' with an rvalue of type 
                                // 'void (D::*)()': different classes ('B' vs 'D')
}
Run Code Online (Sandbox Code Playgroud)

错误消息(至少在 clang 上)非常清楚。gcc 只是说无法初始化。问题只是您无法将派生成员指针隐式转换为基成员指针。但你可以明确地这样做static_cast

void (B::*ptr)() = 
    static_cast<void (B::*)()>(&D::foo); // ok!
Run Code Online (Sandbox Code Playgroud)

旁注:请CALL_MBR_FUNC从代码中删除宏,并且永远不要再写这样的东西。