【问题标题】:Understanding (simple?) C++ Inheritance理解(简单?)C++ 继承
【发布时间】:2011-05-05 11:24:43
【问题描述】:

我有点想明白为什么这段代码 sn-p 无法编译。

#include <cstdio>

class A {
public:
    virtual int potential()=0;
    virtual int potential(int arg, int arg2)=0;
};

class B : public A {
public:
    int potential() { return 1; }
    virtual int potential(int arg, int arg2) { return 2; }
};

class C : public B {
public:
    int potential(int arg, int arg2) { return 3; }
};


int main(int argc, char** argv) {
    C c;
    int value = c.potential();
    printf("Got %i\n", value);
    return 0;
}

我有两个纯虚方法,都在抽象超类A 中命名为potential。子类 B 然后定义了这两个方法,但另一个子类 C 只需要重新定义其中一个方法。

但是,在编译时,只能识别C中定义的方法,而看不到potential()(这应该是继承自B):

In function 'int main(int, char**)':
Line 23: error: no matching function for call to 'C::potential()'
compilation terminated due to -Wfatal-errors.

如果我将A::potential(int, int) 重命名为继承树下的其他名称,例如A::somethingElse(int, int),则代码编译良好,输出为Got 1,正如预期的那样。

这已使用 clangg++ 和 MSVC 的 cl 进行了验证。

有什么想法吗?

【问题讨论】:

  • 按照建议使用&lt;cstdio&gt;

标签: c++ inheritance


【解决方案1】:

但是,在编译时,只能识别 C 中定义的方法,而没有看到 potential()(这应该是从 B 继承的)。

C++ 不能这样工作:因为您在C 中实现了不同的potential 方法(同名但具有不同参数的方法),所以另一个方法隐藏为就C而言。

由于 C++ 解析(重载)方法名称的方式而发生隐藏:当您在类的实例(此处为 c)上调用方法 potential 时,C++ 在类中搜索该名称的方法是否存在。如果不是这种情况,它将继续在基类中搜索。它在层次结构中更靠前,直到找到至少一个该名称的方法。

但在您的情况下,C++ 不必搜索很远:该方法已经存在于 C 中,因此它停止搜索。现在 C++ 尝试匹配方法签名。不幸的是,方法签名不匹配,但此时为时已晚:重载解析失败; C++ 不会搜索可能匹配的其他方法。

有三种解决方案:

  1. 在 C 中使用 using 导入它:

    class C : public B {
    public:
        using B::potential;
        int potential(int arg, int arg2) { return 3; }
    };
    
  2. main中的基类实例调用方法:

    C c;
    B& b = c;
    int value = b.potential();
    
  3. main 中明确限定名称:

    C c;
    int value = c.B::potential();
    

【讨论】:

  • 有趣 - 我以前从未见过像这样使用 using 关键字。其他方法怎么隐藏了?它的签名与定义的方法不同,对吧?
  • @Dan:这就是 C++ 中的继承方式。如果你愿意,可以称之为怪癖。
  • @Dan 我添加了对重载解析和隐藏的解释。
  • 这就是我喜欢 C++ 的原因 =) 怪癖永远不会结束。
  • 三个非常好的替代方法来让事情正常工作。 #3 对我来说也是新的 :) 但我想我会选择 #1。如果我有例如3 种不同的 potential 方法,并且只有 1 个覆盖,using B::potential; 是否会将 B 中的所有方法带入 C 的范围?
【解决方案2】:

问题在于名称隐藏。

函数重载和函数继承并不是最好的朋友。通常你要么 [嗯,三个的“要么”是什么?]

  • 在单个类中重载函数。一切正常。
  • 从基类继承非重载函数。一切正常。
  • 在派生类C 中从基类B 重新实现非重载函数。 C::func 隐藏 B::func 因为它具有相同的名称。

您正在使用继承重载,而您的C::func 隐藏了B::func 以及它的每个重载,即使是那些没有重新-在C中实现。

这对 C++ 有点奇怪,但很容易解决。

简而言之,解决方案是使用using 语句将B::potential() 带入C 的范围:

class C : public B {
public:
    using B::potential; // brings overloads from B into scope
    int potential(int arg, int arg2) { return 3; }
};

我已经写了一篇文章here,深入演示了这个问题。

【讨论】:

  • 您也可以使用 either 三个选项:)
  • @Dan:这不是真正的工作原理,但你不会从我这里得到任何抱怨!是否得到答案才是最重要的。
  • @davka:我不承认“American Heritage® Dictionary of the English Language”是英语的权威。
  • @Tomalak: touchee :) 不过它支持你的情况
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-12-07
  • 1970-01-01
  • 2015-06-05
  • 2011-07-26
  • 1970-01-01
  • 1970-01-01
  • 2023-03-22
相关资源
最近更新 更多