代码之家  ›  专栏  ›  技术社区  ›  mats

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

  •  1
  • mats  · 技术社区  · 16 年前

    我有一个关于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 回复  |  直到 16 年前
        1
  •  1
  •   Bojan Resnik    16 年前

    我怀疑 factoryReg 实际上不会调用回调,但会存储指针,并在发生某些情况时调用回调。

    如果是这样,则此代码:

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

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

    你的 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); 
        }
    };
    
        2
  •  0
  •   mats    16 年前

    好吧,假设specialCallback::entry()以某种方式调用baseCallback::exit()似乎是安全的。 不能100%确定,因为它是封闭源代码——但很可能。

    “回调”函数有很多…