可能性のある複製:
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);
};
次の例では、バーにa(double)関数がないことを示すコンパイルエラーが発生します。
main()
{
double i = 0.0;
bar b;
b.a(i);
}
クラスバーに追加
using foo::a;
これは、C++の一般的な「問題」です。クラスのスコープで名前の一致が見つかると、オーバーロードの継承ツリーはそれ以上検索されません。 「using」宣言を指定することにより、「a」のすべてのオーバーロードを「foo」から「bar」のスコープに移動します。その後、オーバーロードは適切に機能します。
'foo'クラスを使用する既存のコードがある場合、その意味は追加のオーバーロードによって変更される可能性があることに注意してください。または、追加のオーバーロードによってあいまいさが生じ、コードのコンパイルが失敗する可能性があります。これはジェームズ・ホプキンの答えで指摘されています。
それが言語が機能するために使用された方法です。 singキーワードの前に、1つのオーバーロードされた関数をオーバーライドした場合、それらすべてをオーバーロードする必要がありました。
class bar : public foo
{
public:
bar(void);
~bar(void);
a(int);
a(double d) { foo::a(d); } // add this
}
これは、言語委員会がsing機能を追加するのに十分なほどうんざりしていましたが、いくつかの古い習慣はひどく死にます。と習慣†は良い議論を持っています。
James Hopkinsが指摘しているように、singを追加することにより、プログラマーは派生クラスが警告なしに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-このプロモーションが発生したことを警告する警告は表示されません。
メソッドBase :: f(int)を追加して、Baseへの将来の変更をシミュレートするには、コメントを外します(1)。 -Wallを使用しても警告なしでコードがコンパイルされ、「Derived :: Double!」出力のままです。
ここで、コメントを外して(2)、派生プログラマーによるすべてのBase :: fシグニチャーを含めるという決定をシミュレートします。コードは(警告なしで)コンパイルされますが、出力は "Base :: Int!"になります。
—
†「癖のある人」「中毒者」の英単語が強すぎるとは思えない。
仕様によるものです。オーバーロードの解決は、単一のスコープに制限されています。追加の関数が基本クラスまたは名前空間スコープに追加されたときに、有効なコードが意味を変えるいくつかの厄介なケースを防ぎます。