【问题标题】:Issues with C++ template arguments for inheritance用于继承的 C++ 模板参数的问题
【发布时间】:2009-12-10 16:58:50
【问题描述】:

我有一个关于 C++ 模板的问题。更具体地说,通过使用模板参数进行继承。 我在封闭源代码的 3rd 方库中面临奇怪的行为。有一个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 的问题。不确定。

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

【问题讨论】:

  • 你能把这个 pidgin C++ 充实到至少有希望编译的东西吗?用伪代码做语言律师很难。
  • 对不起,我意识到代码有点薄:现在充实它。

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


【解决方案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); 
    }
};

【讨论】:

  • 关于基类方法调用的有效点。我想,要“装饰”一个 SpecialCallback,我会使用“is-a ICallback”和“has-a ICallback”模式。此外,TemplCallback 的状态与包含的 SpecialCallback 实例不同。
  • 关于范围:我们可以假设 ICallback 指针总是有效的(大胆的假设,我知道 - 但我的测试项目只保留在 main() 函数中,因此局部变量的分配没有悬空指针)。
【解决方案2】:

好的,假设 SpecialCallback::ENTRY() 以某种方式调用 BaseCallback::EXIT() 似乎是安全的。 不能 100% 确定,因为它是封闭源代码 - 但很有可能。

“回调”函数就这么多了......

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多