我对C ++模板有疑问。更具体地说,通过使用模板参数进行继承。 我在一个封闭源的第三方库中面临着奇怪的行为。有一个C方法
factoryReg(const char*, ICallback*)
允许注册ICallback的子类并覆盖(简化)方法:
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;
};
我有
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;
}
注册后
SpecialCallback spc("validName");
TemplCallback<SpecialCallback> myCallback(spc);
factoryReg(spc.getName(), &myCallback);
...
// output: "in ENTRY base"
// "in EXIT base"
回调以某种方式不起作用(调试输出没有被放出//断点不适用)。
如果我在模板类TemplCallback中省略了EXIT(void * data)方法的实现 - 一切正常!
// output: "in ENTRY templ."
// "in EXIT base"
这是预期的行为吗?我被告知可能是我使用的MSVC编译器13.10.6030的问题。不确定。
顺便说一句:这里提出的模板构思可能不是我想要做的任何事情的最佳选择;) 但无论设计问题如何,我仍然对此事本身感兴趣。答案 0 :(得分:1)
我怀疑factoryReg
实际上并没有调用回调,而是存储指针并在发生某些事情时调用回调。
如果是这种情况,那么这段代码:
TemplCallback<SpecialCallback> myCallback(spc);
factoryReg(spc.getName(), &myCallback);
导致factoryReg
存储指向临时的指针,一旦注册函数返回,它将超出范围。因此,当调用回调时,对象不活动并且您有未定义的行为。
你的TemplCallback
课看起来很有趣。我不认为你真的希望它使用不同的对象,而是调用继承版本的ENTRY
和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);
}
};
答案 1 :(得分:0)
好吧,似乎可以安全地假设SpecialCallback :: ENTRY()以某种方式调用BaseCallback :: EXIT()。 不能100%肯定,因为它是封闭源 - 但它很可能。
“回调”功能......