20


3

仮想関数が非表示になるのはなぜですか?

私は以下のクラスがあります。

class A {
public:
    virtual void f() {}
};


class B : public A{
public:
    void f(int x) {}
};

私が言うなら

B *b = new B();
b->f();
コンパイラーはエラーC2660: 'B

f’を言います:関数は引数を取りません。 Bの関数は仮想関数なので、それをオーバーロードすべきではありませんか? 仮想関数はこのように隠されますか?

編集:私は確かに、同じ動作を示すAからBを継承するつもりでした。

6 Answer


35


「B」が「A」から派生することを意図していると仮定します。

`f(int)`と `f()`は異なるシグネチャであるため、異なる関数です。

互換性のあるシグネチャを持つ関数で仮想関数を_override_できます。これは、同一のシグネチャか、戻り値の型が「より具体的」である(共分散)ことを意味します。

それ以外の場合、派生クラスが基本クラス関数と同じ名前の関数を宣言する他の場合と同様に、派生クラス関数は仮想関数を隠します。 クラスBに「using A

f;」を入れて名前を再表示できます

あるいは、 (static_cast(b))→ f();、または `b→ A

f();`として呼び出すことができます。 違いは、 B`が実際に f() をオーバーライドする場合、前者はオーバーライドを呼び出しますが、後者は関係なく A`の関数を呼び出すことです。


7


クラスBはAから派生しないため、関数F()は存在しません。 あなたはおそらく意味:

class A {
public:
    virtual void f() {}
};


class B : public A {
public:
    void f(int x) {}
};

*編集:*実際の機能の隠蔽を逃しました。 詳細な説明については、Steve Jessopの回答を参照してください。


4


いいえ、それぞれはい。 過負荷の動作が必要な場合は、言う必要があります

using A::f;

Bで


2


BはAから派生していません。正しい宣言は次のとおりです。

class B : public A


2


コンパイラがシンボルを解決する方法が複数ある場合、コードで特に指示がない限り、どちらの方法が優先されるかを選択する必要があります。 あなたが期待しているのは、オーバーライドよりも優先するオーバーロードです。 (オーバー、オーバー、オーバー、aaaaack! 申し訳ありませんが、「圧倒されました」。

この例には、サブクラスがオーバーロードされたバージョンを提供する仮想メソッドを継承するBがあります。 オーバーロードは、同じメソッド名で異なるシグネチャを使用する同じクラスのメソッド用です。 BはAのサブクラスであるため、f()をオーバーライドしています。つまり、同時にオーバーロードになることはできません。 これが隠されている理由です。

クラスAの場合、メソッドを宣言する

virtual void f() {}

as virtualは、bの宣言と一致しない特定のルールセットを使用してメソッドが解決されることを意味します。

B *b = new B();

「b」のインスタンスとして「b」を作成することにより、コンパイラは「A」の同じ名前のメソッドの仮想的な性質を使用する必要がなくなります。

このように「b」を宣言した場合

B *b = new A();

次に、b→ f()を呼び出します。実際、仮想解像度を利用してAのメソッドを参照します。


2


Biern StroustrupのFAQに回答があるかなり似た質問が存在するようです:http://www.stroustrup.com/bs_faq2.html#overloadderived

彼が言ったように:

_ 「C ++では、スコープ全体にオーバーロードはありません」 _

でももしあなたが欲しければ

_ 「これはusing宣言を使用して簡単に実行できます」 _