继承的C ++模板参数的问题

时间:2009-12-10 16:58:50

标签: c++ inheritance templates visual-c++

我对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的问题。不确定。

顺便说一句:这里提出的模板构思可能不是我想要做的任何事情的最佳选择;) 但无论设计问题如何,我仍然对此事本身感兴趣。

2 个答案:

答案 0 :(得分:1)

我怀疑factoryReg实际上并没有调用回调,而是存储指针并在发生某些事情时调用回调。

如果是这种情况,那么这段代码:

TemplCallback<SpecialCallback> myCallback(spc);
factoryReg(spc.getName(), &myCallback);

导致factoryReg存储指向临时的指针,一旦注册函数返回,它将超出范围。因此,当调用回调时,对象不活动并且您有未定义的行为。

你的TemplCallback课看起来很有趣。我不认为你真的希望它使用不同的对象,而是调用继承版本的ENTRYEXIT

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%肯定,因为它是封闭源 - 但它很可能。

“回调”功能......