我有以下代码。
class BaseHandler
{
//Blank class
};
typedef void (BaseHandler::*InstantFunc)();
class MyDrivedClass: public BaseHandler
{
//Constructor
...
// Data Members
...
char *m_someMember;
...
void DoJob();
//More functions
...
}
MyDrivedClass::DoJob()
{
//accessing Work Something with 'm_someMember' data;
}
class ForCallback
{
public:
ForCallback(BaseHandler* handler, InstantFunc callback);
BaseHandler* GetHandler();
InstantFunc GetCallback();
void Handle(SProgressiveInfo info);
protected:
BaseHandler* m_handler;
InstantFunc m_callback;
};
ForCallback::ForCallback(BaseHandler* handler, InstantFunc callback):
m_handler(handler), m_callback(callback)
{
}
BaseHandler* ForCallback::GetHandler()
{
return m_handler;
}
InstantFunc ForCallback::GetCallback()
{
return m_callback;
}
void ForCallback::Handle()
{
(m_handler->*(m_callback))();
}
//thread1--
somefunction()
{
//Creating mydrivedclass.
MyDrivedClass *drived = new MyDrivedClass();
ForCallback *cBack = new ForCallback(drived, MyDrivedClass::DoJob);
//store cback in some global map
StoreInGlobalMap(cBack);
}
//Thread2---
someotherfunction
{
//Get cback from the global map
ForCallback *cBack = GetFromMap();
cback->Handle();
}
当我在iOS中运行此代码(使用xcode编译)时它工作正常,但是当我在Windows上运行此代码(使用visual studio编译)时,我观察到一些崩溃。
在调查我在处理回调时在thread2中找到的函数' DoJob'被叫,这个'这个' ' MyDrivedClass'的指针无效,我无法访问' m_someMember'。我正在使用互斥锁来同步线程之间的数据,并且没有同步问题。
在调试过程中,我发现在创建' ForCallback'的对象时我们正在传递“MyDrivedClass”的地址。但地址传递给' ForCallback'的构造函数。是不同的。这可能是由于派生类转换为基类指针
我找到的解决方法是将ForCallback的定义更改为
ForCallback::ForCallback(void* handler, InstantFunc callback):
m_handler(()BaseHandler*)handler), m_callback(callback)
{
}
但这仍然是一种解决方法。
请有人解释iOS(Xcode编译)和Windows(Visual Studio 2015编译)上不同行为的原因 什么是适用于iOS和Windows的正确解决方案。
答案 0 :(得分:0)
派生对象的地址可能不同,因为它具有虚方法,而基类则没有。有关说明,请参阅this question。此外,如果使用虚拟继承,则地址也不同。此外,如果使用多重继承,则基类的地址可能不同。
在构造函数中将MyDrivedClass*
转换为BaseHandler*
时,编译器足够聪明,可以适当地更改地址。
但是,成员函数指针强制转换并不是那么清楚。您可以阅读this article以了解它们有多复杂。实际上,您不能简单地将MyDrivedClass
的成员函数指针指向BaseHandler
的成员函数指针,而MSVC2013会告诉您:
temp.cpp(34) : error C2664: 'ForCallback::ForCallback(const ForCallback &)' : cannot convert argument 2 from 'void (__cdecl MyDrivedClass::* )(void)' to 'InstantFunc'
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
另一方面,您可以使用static_cast
或C风格强制转换它。在这种情况下,MSVC2013会警告您:
temp.cpp(34) : warning C4407: cast between different pointer to member representations, compiler may generate incorrect code
我认为在这种情况下调用类型为BaseHandler
的对象的方法是不正确的,因为类BaseHandler
没有这样的方法。所以你在这里称之为不存在的方法。我希望有人能够更好地了解C ++标准。