将派生类成员函数的指针强制转换为抽象成员函数的指针
cast a pointer to member function in derived class to a pointer to abstract member function
我正在尝试做一些似乎应该是相当普遍的,但我一直无法找到任何人讨论它。这篇关于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_ */
和我有一个派生类:
#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_ */
其中function1和function2为:
void aSubClass::function1(aBaseClass_mem_func infunc)
{
CALL_MBR_FUNC(*this, infunc)();
}
void aSubClass::function2(void)
{
A = 42;
B = 66;
}
最后,在main()
中,我尝试在aSubClass
类型的对象上调用function1
,在aSubClass
中传递指向function2
的指针:
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);
}
好,可以自动将指针到派生类型强制转换为指针到基类型。我已经知道,不能将指向派生成员函数的指针传递给指向基成员函数的指针。我想我明白为什么(派生成员函数可能会利用派生类中存在但基类中不存在的东西)。
但我试图建立一个库的两个类别的类(从两个基类派生)。将它们称为baseclass1和baseclass2。来自baseclass1的任何派生类中的一个成员函数需要能够从来自baseclass2的任何派生类中获得一个特定的成员函数。我可以用什么技巧来完成必要的石膏吗?我是否必须使用explicit
关键字并以某种方式定义强制转换?
你可以把这个例子缩短很多:
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
宏,永远不要再写这样的事情了。
为什么不工作:
考虑成员函数的一种方法是: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
[不一定]是Bar
。你可以static_cast
,这是你告诉编译器"不,真的,我很确定我在做什么"的方式(而不是reinterpret_cast
,这是你告诉编译器"你很愚蠢;我知道我在做什么。")
因此,也不允许强制转换成员函数。
另一个答案说static_cast
可以转换成员函数,但这只是因为static_cast
被允许执行隐式强制转换的相反操作(cv-qualification除外)。你可以这样做,但它有相同的警告。
免责声明:这是一个相当简化的规范版本,但它已经传达了要点。
在大多数情况下一个更好的解决方案:
一个[潜在的]更好的解决方案[除非绝对性能是关键]:boost::function
(或,如c++ 11 std::function
)。这是一个函子
成员函数可以这样写:
class Foo {
void function ( boost::function<void()> function ) { }
} ;
functor对象可以用任何可以用指定原型调用的对象来构造(在本例中,是不带参数并返回void
的对象)。例如,您可以传递c函数的地址。
你可以做的另一件事是"绑定"函数(基本上是获取参数并创建一个函数)。这是boost::bind
。
例如:
Foo foo ;
Bar bar ;
foo.function ( boost::bind(&Bar::go2,&bar) ) ;
boost绑定接受某个函数作为第一个参数。如果函数是成员函数,则下一个参数必须是可以调用指定方法的类的实例(在这种情况下,它被复制)或指向可以调用指定方法的类的指针(在这种情况下,它被引用)。这个例子实际上会导致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
的成员函数指针 - 对
foo
实例的引用(或'指针') - "结果函数的第一个参数"的占位符,它将成为调用
go2
的第一个参数。 - 数字2,它将成为调用
go2
的第二个参数
这是将打印到控制台的内容:
1 2
这是一个非常强大的工具,将带领您进入函数式编程的奇妙世界,同时使您的生活更轻松。(这也会让@CortAmmon这样的人讨厌你。)
- QMetaObject invokeMethod的基于函数指针的语法
- C++-试图将函数指针推回到另一个CPP文件中的矢量时出错
- c++r值引用应用于函数指针
- 模板函数指针和lambda
- 是否可以将llvm::FunctionType转换为C/C++原始函数指针
- 带有类的函数指针
- () 函子后面的括号,而不是函数指针?
- 全局作用域中函数指针的赋值
- 使用"Task"函数指针队列定义作业管理器
- 将成员函数指针作为参数传递给模板方法
- 如何创建对象函数指针C++映射?
- 匹配函数指针作为模板参数?
- 通过函数指针定义类范围之外的方法
- 存储在类中的函数指针
- C++从函数指针数组调用函数
- 将返回值存储在函数指针数组的指针中是如何工作的?
- 整数键映射到头文件中的成员函数指针
- 从类成员函数到类 C 函数指针的转换
- 如何将内联匿名函数分配给C++函数指针
- 将字符缓冲区强制转换为函数指针