【问题标题】:Calling a base class method in a template virtual class hierarchy在模板虚拟类层次结构中调用基类方法
【发布时间】:2013-01-14 13:05:52
【问题描述】:

假设我有以下类层次结构:

template< class T >
class TestBase {

public:

    virtual T const & do_foo() = 0;

};

template< class T >
class TestDerived : public virtual TestBase< T > {

public:

    virtual int do_bar() {
        return do_foo() + 1;
    }

};

GCC 吐出以下内容:

error: there are no arguments to ‘do_foo’ that depend on a template parameter, so a declaration of ‘do_foo’ must be available [-fpermissive]
note: (if you use ‘-fpermissive’, G++ will accept your code, but allowing the use of an undeclared name is deprecated)

现在,如果我将其更改为从从已知类型实例化的 TestBase 派生(例如 class TestDerived : public virtual TestBase&lt; int &gt;,此 sn-p 编译得很好,因此问题显然与编译时未知的基类类型有关。但由于我没有在任何地方实例化任何一个类的对象,我不明白这为什么重要。

基本上,如果不求助于-fpermissive,我将如何解决错误?

【问题讨论】:

  • 不应该是virtual T do_bar() in TestDerived吗?
  • @BartekBanachewicz - 我认为没有必要,T 可以是任何类型,例如 decltype(do_foo() + 1) 是一个 int(或者我认为可以隐式转换为一个 int)。
  • 哦,好的。不过,它肯定会触发实例化。

标签: c++ templates virtual


【解决方案1】:

非依赖名称(即不依赖于模板参数的名称)在解析模板时查找,而不是在实例化模板时查找。您需要将do_foo 设为从属名称。基本上有两种方法可以实现:

virtual int do_bar() {
    return this->do_foo() + 1;
}

template< class T >
class TestDerived : public virtual TestBase< T > {

public:
    using TestBase<T>::do_foo;

    virtual int do_bar() {
        return do_foo() + 1;
    }

};

【讨论】:

  • 还有第三种方法:明确限定名称,而不是通过using 导入。
  • @KonradRudolph 那会改变语义。如果您使用我列出的其中一种方式,则动态调度(虚拟调用)正常工作。如果您明确限定,则绕过动态调度。
【解决方案2】:

它不会因为它的美丽而赢得任何奖项,但这段代码按预期工作,编译器没有抱怨。

virtual int do_bar() {
    return ((TestBase<T> *) this)->do_foo() + 1;
}

【讨论】:

  • 你不需要演员表。仅使用 this-&gt; 也可以。
  • 确实,当我尝试这样做时,肯定有其他问题!您的答案更完整;赞成!
  • 谢谢。为了记录,我没有对你投反对票(你的答案本身并没有错)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-12
  • 2015-07-12
  • 1970-01-01
  • 2012-01-13
  • 1970-01-01
相关资源
最近更新 更多