95

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

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){};class から削除するBか、から名前を変更するとfoo1、すべて正常に動作します。

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

4

2 に答える 2

112

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

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 での名前検索の結果を定義します。最初に、クラスとその基本クラスのサブオブジェクトのそれぞれでの名前のすべての宣言が考慮されます。サブオブジェクト B のメンバ名 f は、A が B の基本クラス サブオブジェクトである場合、サブオブジェクト A のメンバ名 f を隠します。そのように隠されている宣言は考慮から除外されます。using-declaration によって導入されたこれらの宣言のそれぞれは、using-declaration によって指定された宣言を含む型である C の各サブオブジェクトからのものであると見なされます。すべて同じ型のサブオブジェクトから、またはセットに非静的メンバーがあり、個別のサブオブジェクトからのメンバーが含まれている場合、あいまいさがあり、プログラムの形式が正しくありません。それ以外の場合、そのセットはルックアップの結果です。

別の場所(そのすぐ上)に次のように記載されています。

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

([...]私が入れました)。これは、B の foo が非公開であっても、A の foo は見つからないことに注意してください (アクセス制御は後で行われるため)。

于 2009-01-04T15:07:40.123 に答える
82

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

基本クラスの関数をオーバーライドすることを意図していないベース クラスの関数と同じ名前を持つ派生クラスの関数を持つことは、一般的に悪い習慣と見なされます。これは、通常、望ましい動作ではないためです。通常は、異なる関数に異なる名前を付けることが望ましいです。

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

于 2009-01-04T15:09:23.537 に答える