55

重複の可能性:
C++ オーバーロードの解決

クラスがその基本クラスの関数をオーバーライドした後、関数のオーバーロードされたバージョンがすべて非表示になるという問題に遭遇しました。これは仕様によるものですか、それとも私が何か間違ったことをしているだけですか?

元。

class foo
{
  public:
    foo(void);
    ~foo(void);
    virtual void a(int);
    virtual void a(double);
};

class bar : public foo 
{
  public:
    bar(void);
    ~bar(void);
    void a(int);
};

次の例では、bar に a(double) 関数がないというコンパイル エラーが発生します。

main() 
{
  double i = 0.0;
  bar b;
  b.a(i);
}
4

3 に答える 3

84

クラスバーに追加

using foo::a;

これは、C++でよくある「落とし穴」です。クラススコープで名前の一致が見つかると、継承ツリーでオーバーロードをさらに検索することはありません。'using'宣言を指定することにより、'foo'からの'a'のすべてのオーバーロードを'bar'のスコープに持ち込みます。その後、オーバーロードは適切に機能します。

'foo'クラスを使用する既存のコードがある場合、その意味は追加のオーバーロードによって変更される可能性があることに注意してください。または、追加のオーバーロードによってあいまいさが生じ、コードのコンパイルに失敗する可能性があります。これは、ジェームズ・ホプキンの答えで指摘されています。

于 2009-05-20T14:34:46.653 に答える
26

それが、かつて言語が機能していた方法です。usingキーワードの前に、1 つのオーバーロードされた関数をオーバーライドすると、それらすべてをオーバーロードする必要がありました。

class bar : public foo 
{
  public:
    bar(void);
    ~bar(void);
    a(int);
    a(double d) { foo::a(d); }  // add this
}

これは、言語委員会がusing機能を追加するほど人々を悩ませましたが、いくつかの古い習慣はなかなか消えません。そして習慣†には良い議論があります。

James Hopkins が指摘しているように、using を追加することで、プログラマーは、派生クラスが警告なしに、受け入れ可能なシグネチャのリストに foo::a() の将来のオーバーライドを追加するという意図を表明しています。

彼が説明する内容の例を次に示します。

#include <iostream>
class Base {
public:
  virtual void f(double){ std::cout << "Base::Double!" << std::endl; }
  // virtual void f(int) { std::cout << "Base::Int!" << std::endl; } // (1)
  virtual ~Base() {}
};

class Derived : public Base {
public:
  // using Base::f; // (2)
  void f(double) { std::cout << "Derived::Double!" << std::endl; }
};

int main(int, char **) {
  Derived d;
  d.f(21);
  return 0;
}

出力は "Derived::Double!" になります。コンパイラは整数引数を double にプロモートするためです。g++ 4.0.1 - Wall は、このプロモーションが発生したことを警告しません。

メソッド Base::f(int) を追加する Base への将来の変更をシミュレートするには、(1) のコメントを外します。このコードは、-Wall と "Derived::Double!" を使用しても警告なしでコンパイルされます。出力のままです。

ここで (2) のコメントを外して、すべての Base::f シグネチャを含めるという Derived プログラマによる決定をシミュレートします。コードは (警告なしで) コンパイルされますが、出力は "Base::Int!" になります。

†「習慣を持っている人」を表す英語の単語が思い浮かびません。「中毒」は強すぎます。

于 2009-05-20T14:31:59.717 に答える
14

仕様によるものです。過負荷の解決は、単一のスコープに制限されています。これにより、基本クラスまたは名前空間スコープに追加の関数が追加されたときに、有効なコードが意味を変えるという厄介なケースを防ぐことができます。

于 2009-05-20T14:38:26.380 に答える