Issues with C++ template arguments for inheritance
I have a questions about C++ templates. More specifally, by using template arguments for inheritance. I am facing strange behaviour in a closed-source 3rd party library. There is a C method
factoryReg(const char*, ICallback*)
which allows to register a subclass of ICallback and overwrite the (simplified) methods:
class ICallback
{
public:
virtual void ENTRY(void* data) = 0;
virtual void EXIT(void* data) = 0;
const char* getName() { return _name; } const
ICallback(const char* name) : _name(name) {}
virtual ~ICallback() {}
private:
const char* _name;
};
I have
class BaseCallback : public ICallback
{
public:
BaseCallback(const char* name) : ICallback(name) {}
virtual void ENTRY(void* data) {
std::cout << "in ENTRY base" << std::endl;
}
virtual void EXIT(void* data) {
std::cout << "in EXIT base" << std::endl;
};
class SpecialCallback : public BaseCallback
{
public:
SpecialCallback(const char* name) : BaseCallback(name) {}
virtual void ENTRY(void* data) {
// actually, it's 3rd party code too - assumed to do something like
...
BaseCallback::ENTRY();
}
// no redecl. of EXIT(void* data)
};
template <typename Base>
TemplCallback : public Base
{
public:
TemplCallback(Base& myT) : Base(myT.getName()), _myT(myT)
virtual void ENTRY(void* data) {
std::cout << "in ENTRY templ." << std::endl;
_myT.ENTRY();
}
virtual void EXIT(void* data) {
std::cout << "in EXIT templ." << std::endl;
_myT.EXIT();
}
private:
Base& _myT;
}
Upon registering
SpecialCallback spc("validName");
TemplCallback<SpecialCallback> myCallback(spc);
factoryReg(spc.getName(), &myCallback);
...
// output: "in ENTRY base"
// "in EXIT base"
the callback somehow does not work (debug output not being put out // breakpoints do not apply).
If I omit implementation of the EXIT(voi开发者_如何学运维d* data) method in my template class TemplCallback - everything works fine!
// output: "in ENTRY templ."
// "in EXIT base"
Is this expected behaviour? I have been told it might be an issue of the MSVC compiler 13.10.6030 I use. Not sure about that.
BTW: The template idea presented here might not be the best choice for whatever I am trying to do ;) But I am still interested in the matter itself, regardless about design questions.
I suspect that factoryReg
doesn't actually invoke the callback, but stores the pointer and invokes the callback when something happens.
If that is the case, then this code:
TemplCallback<SpecialCallback> myCallback(spc);
factoryReg(spc.getName(), &myCallback);
causes factoryReg
to store pointer to a temporary, which will go out of scope as soon as your registration function returns. Thus, when the callback is invoked, the object is not alive and you have undefined behaviour.
Your TemplCallback
class looks funny. I don't think you actually want it to use a different object, but to invoke the inherited versions of ENTRY
and EXIT
:
template <class Base>
class TemplCallback : public Base
{
public:
TempCallback(const char* name) : Base(name)
{}
virtual ENTRY(void* data)
{
// do special processing
Base::ENTRY(data);
}
virtual EXIT(void* data)
{
// do special processing
Base::EXIT(data);
}
};
OK, it seems that it is safe to assume that SpecialCallback::ENTRY() calls BaseCallback::EXIT() somehow. Can't be 100% sure, because it's closed source - but it's quite likely.
So much for "callback" functions...
精彩评论