简体   繁体   English

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

[英]Issues with C++ template arguments for inheritance

I have a questions about C++ templates. 我对C ++模板有疑问。 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 有C方法

factoryReg(const char*, ICallback*)

which allows to register a subclass of ICallback and overwrite the (simplified) methods: 它允许注册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;
};

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(void* data) method in my template class TemplCallback - everything works fine! 如果我在模板类TemplCallback中省略了EXIT(void * data)方法的实现,则一切正常!

// 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. 我被告知这可能是我使用的MSVC编译器13.10.6030的问题。 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. 我怀疑factoryReg实际上并没有调用回调,而是存储了指针并在发生某些情况时调用了回调。

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. 使factoryReg存储指向一个临时指针,该指针将在您的注册函数返回后立即超出范围。 Thus, when the callback is invoked, the object is not alive and you have undefined behaviour. 因此,在调用回调时,该对象不是活动的,并且您具有未定义的行为。

Your TemplCallback class looks funny. 您的TemplCallback类看起来很有趣。 I don't think you actually want it to use a different object, but to invoke the inherited versions of ENTRY and EXIT : 我认为您实际上并不希望它使用其他对象,而是调用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); 
    }
};

OK, it seems that it is safe to assume that SpecialCallback::ENTRY() calls BaseCallback::EXIT() somehow. 好的,可以肯定地假设SpecialCallback :: ENTRY()以某种方式调用BaseCallback :: EXIT()。 Can't be 100% sure, because it's closed source - but it's quite likely. 不能100%确定,因为它是封闭源代码-但很有可能。

So much for "callback" functions... “回调”功能就这么多...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM