将指针从派生类方法转换为基类
Casting pointer form derived class method to base class
假设我想创建一个层次结构,该层次结构对以字符串编码的特定事件做出反应。例如来自网络的命令。设想有一个Base
类,处理网络连接、接收缓冲区、分割缓冲区等,处理命令反应,在派生类中(派生类也可以添加一些要处理的新单词)。所以我的解决方案是:
class Base {
public:
typedef void (Base::*Method)();
typedef std::unordered_map<std::string, Method> Methods;
void reactToA();
void reactToB();
Base() :
methods{
{ "A", &Base::reactToA },
{ "B", &Base::reactToB }
}
{
}
void action( const std::string &s )
{
auto f = methods.find( s );
if( f != methods.end() )
(*this.*)(f->second)();
}
protected:
Methods methods;
};
class Child : public Base {
public:
void reactToB();
void reactToC();
Child() {
methods[ "B" ] = static_cast<Method>( &Child::reactToB );
methods[ "C" ] = static_cast<Method>( &Child::reactToC );
}
};
所以我必须将指向Child
方法的指针转换为指向Base
方法的指针。这个cast定义好了吗?是否有更优雅(或正确,如果这导致UB)的解决方案?
From [expr.static.cast]:
类型为"指向cv1
T
类型的D
成员的指针"的右值可以转换为类型为"指向的指针"的右值类型cv2T
的B
' '成员,其中B
是D
的基类(第10条),如果从存在"指向B
的T
类型成员的指针"到"指向D
的T
类型成员的指针"(4.11),cv2也一样cv-qualification等于或大于cv-qualification, cv1。[…如果类B
包含原始成员,或者是包含原始成员的类的基类或派生类,结果指向成员的指针指向原始成员。
在本例中,&Base::reactToB
可以转换为&Child::reactToB
,但由于Base
不包含原始成员,因此行为未定义。
你必须存储std::function<void(Base*)>
或void(*)(Base*)
之类的东西。
如果是前者,您可以向Base
添加成员函数,如:
template <typename C>
void addMethod(std::string const& name, void (C::*method)()) {
methods[name] = [method](Base* b){
(static_cast<C*>(b)->*method)();
};
}
addMethod("B", &Child::reactToB);
如果是后者,可以这样做:
methods[ "B" ] = +[](Base* b){
static_cast<Child*>(b)->reactToB();
};
使用泛型函数指针std::function
的一小部分开销,您可以拥有完全定义的行为和更大的灵活性,因为您可以调用几乎任何东西,而不仅仅是方法:
class Base {
public:
typedef std::function<void()> Callable;
typedef std::unordered_map<std::string, Callable> Callables;
void action(const std::string &s) {
auto f = callables.find(s);
if (f != callables.end()) f->second();
}
protected:
Callables callables;
};
class Derived1 : public Base {
void reactToA() {}
void reactToB() {}
public:
Derived1() {
callables["A"] = std::bind(&Derived1::reactToA, *this);
callables["B"] = std::bind(&Derived1::reactToB, *this);
}
};
static void reactToE();
class Derived2 : public Derived {
void reactToB() {}
void reactToC() {}
public:
Derived2() {
callables["B"] = std::bind(&Derived2::reactToB, *this);
callables["C"] = std::bind(&Derived2::reactToC, *this);
callables["D"] = []{ std::cout << "Hey, what, D now?!" << std::endl; }
callables["E"] = &reactToE;
}
};
相关文章:
- 从基类实例调用派生类方法而不进行强制转换
- C++将派生类转换为基类时'object slicing'期间发生的情况
- 派生类(构造函数具有参数)和基类(构造函数缺少参数)之间没有可行的转换
- 调用不在基类中的派生类函数而不进行动态强制转换,以最大程度地提高性能
- 在将派生类指针类型转换为派生类指针后,从基类指针调用派生类函数
- 我们可以在不知道其真实类型的情况下将基类指针转换为派生类指针吗?
- 从未使用过到基类的转换
- 基类到派生类的强制转换向量
- 有没有办法复制派生类指针的向量而不将其强制转换为基类?
- 为什么此代码不将基类强制转换为 c++ 中的派生类?
- 如何在运行时将指向派生类的 void* 正确转换为指向基类的 void*
- 从基类的共享指针向下转换到派生类的引用
- 为了访问方法,从基类动态转换为派生类
- 派生类 插入和提取运算符重载以及基类与派生类之间的强制转换
- 将空基类优化对象强制转换为另一种类型是否会破坏严格的别名?
- 基类到派生模板类的强制转换指针,而不知道类型
- 带有基类指针的强制转换向量,指向子类
- 通过转换基类指针来设置派生类字段
- 强制转换基类问题
- 强制转换基类保护方法的返回指针的替代方法