向下转换指向成员函数的指针。这是合法的用法吗?
Downcasting pointer to member function. Is this legal usage?
我将指向成员函数的指针列表存储在一个数组中。我想索引到数组中并执行适当的函数。将有许多数组列出来自不同 classes 的函数(全部派生自 Base),因此 class 在编译时是未知的。
我的方案有效,但我对不得不在一个地方使用 void 指针并不完全满意,但我似乎无法避免它。
根据 C++11 标准(它使用 g++),我在 Base 和 Derived 成员函数指针之间的转换是否合法。我将不胜感激语言律师的建议!
下面是我的代码的一个精简但可运行的版本。
#include <iostream>
using std::cout;
//*************************************
class Base {
public:
typedef int (Base::*BaseThunk)();
virtual int execute(BaseThunk x) {return 0;}
};
//*************************************
class Derived : public Base {
public:
typedef int (Derived::*DerivedThunk)();
int execute(BaseThunk step) {
return (this->*step)(); //Is this OK ? step is really a DerivedThunk.
}
int f1() { cout<<"1\n";return 1;}
int f2() { cout<<"2\n";return 2;}
int f3() { cout<<"3\n";return 3;}
static DerivedThunk steps[];
};
//Here is an array of pointers to member functions of the Derived class.
Derived::DerivedThunk Derived::steps[] = {&Derived::f1, &Derived::f2, &Derived::f3};
//*************************************
class Intermediate : public Base {
public:
void f(void *x) { //I am worried about using void pointer here !
BaseThunk *seq = reinterpret_cast<BaseThunk *>(x);
Derived d;
d.execute(seq[2]);
}
};
//*************************************
int main() {
Intermediate b;
b.f(&Derived::steps);
}
您对 void*
的担忧是有根据的:这是 未定义的行为 因为(在 Intermediate::f
中)您正在执行指针运算并读取通过,一个与数组类型不匹配的指针。
好消息是有一个简单的解决方法:因为你的数组的目的是让 derived-class 函数在只给定一个 Base&
和一个 BaseThunk
的情况下被调用,你可以 存储 类型:
Base::BaseThunk Derived::steps[]=
{static_cast<BaseThunk>(&Derived::f1),
…};
static_cast
有点冗长,但只要您 使用 生成的 BaseThunk
对象的对象类型是 或 是完全合法的源自 Derived
。您甚至不必先获得 Derived*
:
int Base::execute(BaseThunk x) // no need to be virtual
{return (this->*x)();}
我将指向成员函数的指针列表存储在一个数组中。我想索引到数组中并执行适当的函数。将有许多数组列出来自不同 classes 的函数(全部派生自 Base),因此 class 在编译时是未知的。
我的方案有效,但我对不得不在一个地方使用 void 指针并不完全满意,但我似乎无法避免它。
根据 C++11 标准(它使用 g++),我在 Base 和 Derived 成员函数指针之间的转换是否合法。我将不胜感激语言律师的建议!
下面是我的代码的一个精简但可运行的版本。
#include <iostream>
using std::cout;
//*************************************
class Base {
public:
typedef int (Base::*BaseThunk)();
virtual int execute(BaseThunk x) {return 0;}
};
//*************************************
class Derived : public Base {
public:
typedef int (Derived::*DerivedThunk)();
int execute(BaseThunk step) {
return (this->*step)(); //Is this OK ? step is really a DerivedThunk.
}
int f1() { cout<<"1\n";return 1;}
int f2() { cout<<"2\n";return 2;}
int f3() { cout<<"3\n";return 3;}
static DerivedThunk steps[];
};
//Here is an array of pointers to member functions of the Derived class.
Derived::DerivedThunk Derived::steps[] = {&Derived::f1, &Derived::f2, &Derived::f3};
//*************************************
class Intermediate : public Base {
public:
void f(void *x) { //I am worried about using void pointer here !
BaseThunk *seq = reinterpret_cast<BaseThunk *>(x);
Derived d;
d.execute(seq[2]);
}
};
//*************************************
int main() {
Intermediate b;
b.f(&Derived::steps);
}
您对 void*
的担忧是有根据的:这是 未定义的行为 因为(在 Intermediate::f
中)您正在执行指针运算并读取通过,一个与数组类型不匹配的指针。
好消息是有一个简单的解决方法:因为你的数组的目的是让 derived-class 函数在只给定一个 Base&
和一个 BaseThunk
的情况下被调用,你可以 存储 类型:
Base::BaseThunk Derived::steps[]=
{static_cast<BaseThunk>(&Derived::f1),
…};
static_cast
有点冗长,但只要您 使用 生成的 BaseThunk
对象的对象类型是 或 是完全合法的源自 Derived
。您甚至不必先获得 Derived*
:
int Base::execute(BaseThunk x) // no need to be virtual
{return (this->*x)();}