views:

142

answers:

2

Dear developers,

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(void* 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.

+1  A: 

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); 
    }
};
Bojan Resnik
Valid point about invocation of the base class methods. I thought, to "decorate" a SpecialCallback I would use the "is-a ICallback" and "has-a ICallback" pattern. The TemplCallback, furthermore, is of a different state than the containing SpecialCallback instance.
msiemeri
About scope: We may assume that the ICallback pointer is always valid (bold assumption, I know - but my test project only remains in a main() function, so no dangling pointers from assignment of local variables).
msiemeri
A: 

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...

msiemeri