C ++:方法重载的奇怪行为

时间:2015-08-19 17:12:19

标签: c++ virtual-functions

我需要解释为什么以下代码无法编译。我有一个解决方法,我将在下面阐述,但我不了解原始版本的失败。

加速代码读取:概念是定义一个接口(ISomething),然后创建一个抽象实现(ASomething),它使用第一个函数实现第二个函数(2) (尚未定义)一个(1)。从抽象实现派生的完整实现(例如SomethingImpl)必须定义第一个方法,并且可以覆盖第二个方法。

#include <iostream>

class ISomething
{
public:
  virtual ~ISomething()
  { }
  virtual int f(int x) = 0; // (1)
  virtual int f(int x, int y) = 0; // (2)
};

class ASomething
  : public virtual ISomething
{
public:
  virtual int f(int x, int y) // (2)
  {
    return f(x) + f(y); // (3)
  }
};

class SomethingImpl
  : public ASomething
{
public:
  virtual int f(int x) // (1)
  {
    return x+1;
  }
};

int main()
{
  SomethingImpl a;
  std::cout << a.f(10) << std::endl; // (1)
  std::cout << a.f(10,20) << std::endl; // (2)
  return 0;
}

编译此代码会在Visual Studio 2013(Windows)和g ++ 4.4.5(Linux)上产生错误。错误非常相似,我将仅详细说明g ++输出:

$ g++     SibFun.cpp   -o SibFun
SibFun.cpp: In member function ‘virtual int ASomething::f(int, int)’:
SibFun.cpp:18: error: no matching function for call to ‘ASomething::f(int&)’
SibFun.cpp:16: note: candidates are: virtual int ASomething::f(int, int)
SibFun.cpp:18: error: no matching function for call to ‘ASomething::f(int&)’
SibFun.cpp:16: note: candidates are: virtual int ASomething::f(int, int)
SibFun.cpp: In function ‘int main()’:
SibFun.cpp:36: error: no matching function for call to ‘SomethingImpl::f(int, int)’
SibFun.cpp:26: note: candidates are: virtual int SomethingImpl::f(int)
make: *** [SibFun] Error 1

我尝试在(3) return this->f(x) + this->f(y)使用不同的表示法,但我没有在错误消息中发生重大变化。

然而,当我将(3)更改为return ISomething::f(x) + ISomething::f(y);时,我才得到:

$ g++     SibFun.cpp   -o SibFun
SibFun.cpp: In function ‘int main()’:
SibFun.cpp:36: error: no matching function for call to ‘SomethingImpl::f(int, int)’
SibFun.cpp:26: note: candidates are: virtual int SomethingImpl::f(int)
make: *** [SibFun] Error 1

但是!将(2)f更改为g时,所有内容都会按预期进行编译和运行。

这个乞求背后的原因是什么?为什么我不能使用f的{​​{1}}名称?

3 个答案:

答案 0 :(得分:7)

函数重载仅适用于同一范围内可见的函数:

from gensim import models
w = models.Word2Vec()
w.load_word2vec_format('GoogleNews-vectors-negative300.bin', binary=True)
print w["queen"]

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-3-8219e36ba1f6> in <module>()
----> 1 w["queen"]

C:\Anaconda64\lib\site-packages\gensim\models\word2vec.pyc in __getitem__(self, word)
    761 
    762         """
--> 763         return self.syn0[self.vocab[word].index]
    764 
    765 

AttributeError: 'Word2Vec' object has no attribute 'syn0'

答案 1 :(得分:4)

两个编译失败都是出于同样的原因。当你覆盖一个虚拟成员函数时,你隐藏了另一个。在$(document.body)

ASomething

virtual int f(int x, int y) // (2) { return f(x) + f(y); // (3) } 上的名称查找找到f并停止,它不会继续寻找其他重载。由于ASomething::f有两个参数,而你试图用一个参数调用它,因此错误。为了允许对基类进行重载,必须使用 using-declaration 引入基类成员函数:

ASomething::f

同样地,using ISomething::f; // NOW, ISomething::f(int ) is found by lookup virtual int f(int x, int y) { return f(x) + f(y); } 需要SomethingImpl语句,以便using ASomething::f;可以编译。

答案 2 :(得分:1)

问题不在于超载&#39;问题,但隐藏基类功能(见其他答案)

稍加修改的示例:

#include <iostream>

class ISomething
{
    public:
    virtual ~ISomething() {}
    virtual int f(int x) = 0; // (1)
    virtual int f(int x, int y) = 0; // (2)
};

class ASomething: public virtual ISomething
{
    public:
    virtual int f(int x, int y) // (2)
    {
        // `this->f(x)` fails: 
        ISomething& i = *this;
        return i.f(x) + i.f(y); // (3)
    }
};

class SomethingImpl: public ASomething
{
    public:
    virtual int f(int x) // (1)
    {
        return x+1;
    }
};

int main()
{
    SomethingImpl a;
    // `a.f(10, 20)` fails:
    ISomething& i = a;
    std::cout << i.f(10) << std::endl; // (1)
    std::cout << i.f(10, 20) << std::endl; // (2)
    return 0;
}

因此,从界面调用f可以解决冲突。虽然,您应该考虑using base::f,如其他答案所示。