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

时间:2015-07-24 02:26:10

标签: c++ inheritance member-function-pointers

我正在尝试做一些似乎的事情,因为它应该相当常见,但我一直无法找到任何人讨论它。 this post on stackoverflow类似于我正在尝试做的事情,但并不完全相同。

我有一个抽象的基类:

bool queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
                           struct delayed_work *dwork, unsigned long delay)
{
        struct work_struct *work = &dwork->work;
        bool ret = false;
        unsigned long flags;

        /* read the comment in __queue_work() */
        local_irq_save(flags);

        if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))) {
                __queue_delayed_work(cpu, wq, dwork, delay);
                ret = true;
        }

        local_irq_restore(flags);
        return ret;
}

我有一个派生类:

#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_ */

其中function1和function2是:

#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_ */

最后,在void aSubClass::function1(aBaseClass_mem_func infunc) { CALL_MBR_FUNC(*this, infunc)(); } void aSubClass::function2(void) { A = 42; B = 66; } 我尝试针对main()类型的对象调用function1,将指针传递给aSubClass中的function2:< / p>

aSubClass

好的,我们可以自动将指向派生类型转换为指向基类型。我现在已经读过,我们不能将指向派生的成员函数传递给指向基类成员函数的指针。我想我理解为什么(派生成员函数可能会使用派生类中存在但在基类中不存在的东西)。

但我正在尝试构建一个包含两类类的库(从两个基类派生)。称它们为baseclass1和baseclass2。来自baseclass1的任何派生类中的一个成员函数需要能够从baseclass2的任何派生类中传递特定的成员函数。我可以用一些技巧来进行必要的演员吗?我是否必须使用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); } 关键字并以某种方式定义演员?

2 个答案:

答案 0 :(得分:2)

为什么它不起作用:

你能想到成员函数的一种方法是:

struct Foo {
    void go () { }
} ;

也可以表示为:

void go ( Foo* this ) { }

所以,这个:

typedef void(Foo::*MemberFunctionPtr)() ;

有点像这样:

typedef void(*MemberFunctionPtrForFoo)(Foo*) ;

但是,如果您有这样的子类:

struct Bar : public Foo {
    void go2 () { }
} ;

这个功能也是这样的:

void go2 ( Bar* this ) { }

因此,当您获取Bar::go2的地址时,您基本上会得到一个指向void go2 ( Bar* this )的函数的指针。为什么这是一个问题?

好吧,让我们来看看这意味着什么...

如果你有这个功能:

void function ( Foo * this ) ;

你要做到这一点:

Bar * bar = new Bar () ;
function ( bar ) ;

这会起作用(应该如此)。 C ++让你有可能做到这样的事情:

void(*functionPtr)(Bar*) = &Foo::go ;

但是,让我们说你有这个功能:

void function ( Bar * this ) ;

你这样做了:

Foo * foo = new Foo() ;
function ( foo ) ;

这不会起作用,因为foo不一定是[{1}}。你可以Bar,这是你告诉编译器的方式&#34;不,真的,我很确定我知道我在做什么&#34; (而不是static_cast,这是告诉编译器的方式&#34;你是愚蠢的;我知道我在做什么。&#34;)

因此,它也不允许你施放成员函数。

另一个答案说reinterpret_cast可以转换成员函数,但这只是因为允许static_cast执行隐式强制转换的反向(cv-qualification除外)。你可以做到,但它有相同的警告。

免责声明:这是规范的一个相当简化的版本,但它得到了重点。

大多数情况下更好的解决方案:

一个[可能]更好的解决方案[除非绝对性能是关键]:static_cast(或者,从C ++ 11 boost::function开始)。这是一个&#34;仿函数&#34;。

您的会员功能可以写成:

std::function

可以使用指定原型调用的任何东西构造仿函数对象(在这种情况下,不带参数的东西并返回class Foo { void function ( boost::function<void()> function ) { } } ; )。例如,您可以传递C函数的地址。

你可以做的另一件事是&#34; bind&#34;函数(基本上抓取参数并生成函数)。为此我们void

例如,你可以这样做:

boost::bind

boost bind将一些函数作为第一个参数。如果函数是成员函数,则下一个参数必须是可以调用指定方法的类的实例(在这种情况下它被复制)或指向类的指针可以调用指定的方法on(在这种情况下引用它)。此示例实际上会导致Foo foo ; Bar bar ; foo.function ( boost::bind(&Bar::go2,&bar) ) ; 实例调用foo实例(而不是自身),但您可以改为bar

你甚至可以更有创意:

&foo

那个绑定抓住了:

  • class Foo { void function ( boost::function<void(int)> function ) { function ( 1 ) ; } void go2 ( int a , int b ) { cout << a << " " << b << endl ; } } ; Foo foo ; foo.function ( boost::bind(&Foo::go2,&foo,_1,2) ) ;
  • 的成员函数指针
  • Foo::go2
  • 实例的引用(或&#39;指针&#39;)
  • 占位符&#34;结果函数的第一个参数,&#34;它将成为foo
  • 调用中的第一个参数
  • 数字2,它将成为go2
  • 调用中的第二个参数

这是打印到控制台的内容:

go2

这是一个非常强大的工具,可以引导您进入功能编程的梦幻世界,同时让您的生活更轻松。 (它也会让像@CortAmmon这样的人讨厌你。)

答案 1 :(得分:1)

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

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')
}

错误信息,至少在clang上,非常清楚。 gcc只是说无法初始化。问题只是你不能隐式地将指向派生的成员转换为指向基础成员的指针。但您可以使用static_cast

明确

void (B::*ptr)() = 
    static_cast<void (B::*)()>(&D::foo); // ok!

附注:请从代码中删除CALL_MBR_FUNC宏,再也不要写这样的东西了。