非コンスト仮想メソッドをオーバーライドすると、const過負荷が隠されていますか?
-
08-10-2019 - |
質問
検討:
#include <iostream>
using namespace std;
struct A {
virtual void f() { cout << "A::f" << endl; }
virtual void f() const { cout << "A::f const" << endl; }
};
struct B : public A {};
struct C : public A {
virtual void f() { cout << "C::f" << endl; }
};
int main()
{
const B b;
b.f(); // prints "A::f const"
const C c;
c.f();
// Compile-time error: passing ‘const C’ as ‘this’ argument of
// ‘virtual void C::f()’ discards qualifiers
}
(私はGCCを使用しています。)
f()のconstバージョンはCに隠されているようです。これは私にとって非常に理にかなっていますが、標準によって義務付けられていますか?
解決
これを(もう一度)リンクします 記事 :
まず、[コンパイラ]は即時の範囲(この場合はクラスCの範囲を調べ、Fが見つけることができるすべての関数のリストを作成します(アクセス可能かどうかに関係なく、または適切な数の数を取るかどうかに関係なくパラメーター)。 それが行われない場合にのみ、次の囲まれたスコープに「外向き」を続けます [...]
そうです、 const
のバージョン f
隠されており、それは完全に正常です。 Simoneが指摘したように、あなたは using
もたらす声明 A::f
の C
範囲。
他のヒント
はい、そうです。あなたは書くことができます:
struct C : public A {
virtual void f() { cout << "C::f" << endl; }
using A::f;
};
コードをコンパイルするには:
int main()
{
const B b;
b.f(); // prints "A::f const"
const C c;
c.f(); // prints "A::f const"
}
その他の情報については、2010年のC ++ドラフトドキュメントを参照できます(これを見つけることができます ここ)第10.2章(3-4)。
ベースメンバーを隠すのは仮想性やconst-and(またはその欠如)ではなく、派生した方法は同じ名前のベースメソッドを隠します。これは、脆弱な基本クラスの問題を改善するために行われました。
あなたのコードが以下のように(おそらく何年も)機能していたと想像してください。
struct Base {
};
struct Derived : Base {
void f(double);
}
void g(Derived &d) {
d.f(42);
}
次に、ベースを変更して、まったく違うことを行う方法を含める必要がありますが、何らかの理由で、「F」という名前を付けたいと思います。
struct Base {
void f(int);
};
このルールがなければ、 毎日 派生した呼び出しFの使用は手動で評価する必要があります。そして、ベースが他の人に与えられたライブラリにある場合、他の用途にもアクセスできない場合があります。ユーザー定義(暗黙の)変換に直面して悪化します。
代わりに、宣言を使用してベースから与えられた名前をインポートすることを明示的に述べるために、派生クラスを要求することが決定されました。このルールは驚くかもしれませんし、今日の言語に対する純利益であるかどうかはわかりませんが、彼らは私に尋ねませんでした - 当時、私はおそらく2音節の言葉でしか答えられなかったでしょう。 :)
入れる using B::f;
struct C : public A {
using A::f;
virtual void f() { cout << "C::f" << endl; }
};
C ++Standard2003。13.2P.1:
同じ名前の2つの関数宣言は、同じ範囲にあり、同等のパラメーター宣言(13.1)がある場合、同じ関数を指します。派生クラスの関数メンバー ではありません 基本クラスの同じ名前の関数メンバーと同じ範囲で。
したがって C::f
すべてを隠します A::f
.