名前は同じだがシグネチャが異なる関数


91

同じ名前の関数がありますが、基本クラスと派生クラスで署名が異なります。派生クラスから継承する別のクラスで基本クラスの関数を使用しようとすると、エラーが発生します。次のコードを参照してください。

class A
{
    public:
    void foo(string s){};
};

class B : public A
{
    public:
    int foo(int i){};
};

class C : public B
{
    public:
    void bar()
    {
        string s;
        foo(s);
    }
};

gccコンパイラーから次のエラーを受け取ります。

In member function `void C::bar()': no matching function for call to `C::foo(std::string&)' candidates are: int B::foo(int)

int foo(int i){};クラスから削除した場合B、または名前を変更した場合foo1、すべて正常に動作します。

これの何が問題なのですか?


1
技術的にはこの質問の複製ですが、これはより良いタイトルと回答を持っています。
Troubadour 2011

回答:


77

基本クラスの関数をオーバーライドしないが同じ名前の派生クラスの関数は非表示になります他の関数をます。

表示されているものが通常望ましい動作ではないため、基本クラスの関数をオーバーライドすることを目的としていない、低音クラスの関数と同じ名前の派生クラスに関数を含めることは、一般的に悪い習慣と見なされています。通常、関数ごとに異なる名前を付けることが推奨されます。

基本関数を呼び出す必要がある場合は、を使用して呼び出しのスコープを設定する必要がありますA::foo(s)。これは同時に仮想機能メカニズムも無効にすることに注意してくださいA::foo(string)


13
またlitdbの答えを読む:あなたはBの句「A :: FOOを使用して」で「再表示」ベース機能することができます
xtofl

確かに、基本階層を修正済みとして扱い、呼び出しサイトで使用できるソリューションを見ていました。
CBベイリー

2
この主張の根拠は何であり、次のアドバイスが続きます。「基本クラスの関数をオーバーライドすることを目的としていない、バスクラスの関数と同じ名前を持つ関数を派生クラスに含めることは、一般的に悪い習慣考えられています。何を見ていることが通常望ましい動作ではありません。異なる機能に異なる名前を与えることは通常望ましいです。彼らが意味的に同じことをしている場合はどうなりますか?C ++は、ヨハネスの回答で説明されているように、これによって引き起こされる問題の解決策を提供します。
Nawaz

107

これは、ベースの1つで名前が見つかると、名前の検索が停止するためです。それは他の拠点ではそれ以上には見えません。B の関数はAの関数をシャドウします。B のスコープでAの関数を再宣言して、BとCの両方から両方の関数が見えるようにする必要があります。

class A
{
    public:
    void foo(string s){};
};

class B : public A
{
    public:
    int foo(int i){};
    using A::foo;
};

class C : public B
{
    public:
    void bar()
    {
        string s;
        foo(s);
    }
};

編集:標準が与える実際の説明は次のとおりです(10.2 / 2から):

次の手順では、クラススコープCでの名前検索の結果を定義します。最初に、クラスとその各基本クラスサブオブジェクトでの名前のすべての宣言が検討されます。1つのサブオブジェクトBのメンバー名fは、AがBの基本クラスサブオブジェクトである場合、サブオブジェクトAのメンバー名fを非表示にします。非表示になっている宣言は考慮されません。using-declarationによって導入されたこれらの各宣言は、using-declarationによって指定された宣言を含む型のCの各サブオブジェクトからのものであると見なされます。96)結果の宣言セットが同じタイプのサブオブジェクトからのすべて、またはセットに非静的メンバーがあり、異なるサブオブジェクトからのメンバーが含まれている場合、あいまいさがあり、プログラムの形式が正しくありません。それ以外の場合、そのセットはルックアップの結果です。

別の場所(そのすぐ上)で言うには次のようになります。

id-expression [ "foo"のようなもの ]の場合、名前の検索はこのクラスのスコープで始まります。修飾ID [ 「A :: foo」のようなもので、Aはネストされた名前指定子です ]の場合、名前の検索はネストされた名前指定子のスコープから始まります。名前の検索は、アクセス制御の前に行われます(3.4、11節)。

([...]私が置いた)。つまり、Bのfooがプライベートであっても、Aのfooはまだ見つかりません(後でアクセス制御が発生するため)。


litb、あなたの答えをありがとう。しかし、コードをコンパイルしようとするvoid A::foo(class basic_string<char,char_traits<char>,allocator<char> >)' in と、同じ名前のローカルメソッド `int B :: foo(int) 'があるため、クラスB へのアクセスを調整できません。古いバージョンのgccを使用しているためかもしれません
Igor Oks

1
ええ、間違いなくコンパイラのバグです。「A :: foo;」を使用していた古いコンパイラ 「A :: foo;を使用する」の代わりに ただし、前者はC ++では非推奨です。
ヨハネスシャウブ-litb 2009年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.