5

3 つのクラスがあるとします。

class X{};
class Y{};
class Both : public X, public Y {};

つまり、2 つのクラスがあり、その両方を拡張する 3 番目のクラス (多重継承) があります。

ここで、別のクラスで定義された関数があるとします。

void doIt(X *arg) { }
void doIt(Y *arg) { }

そして、両方のインスタンスでこの関数を呼び出します。

doIt(new Both());

これにより、関数呼び出しがあいまいであることを示すコンパイル時エラーが発生します。

これ以外に、C++ コンパイラが呼び出しがあいまいであると判断し、エラーをスローするケースはありますか? コンパイラはこれらのケースが何であるかをどのように判断しますか?

4

6 に答える 6

8

シンプル: あいまいな場合、コンパイラはエラーを表示し、選択を迫ります。あなたのスニペットでは、 の型がnew Both()へのポインターBothであるのに対し、 の両方のオーバーロードがdoIt()値によってパラメーターを受け入れる (つまり、ポインターを受け入れない) ため、別のエラーが発生します。doIt()タイプX*とそれぞれの引数を取るように変更した場合Y*、コンパイラーはあいまいな関数呼び出しに関するエラーを返します。

どちらか一方を明示的に呼び出したい場合は、引数を適切にキャストします。

void doIt(X *arg) { }
void doIt(Y *arg) { }
Both *both = new Both;
doIt((X*)both);  // calls doIt(X*)
doIt((Y*)both);  // calls doIt(Y*)
delete both;
于 2008-12-22T04:33:36.507 に答える
5

gcc で次のエラーが発生します。

jeremy@jeremy-desktop:~/Desktop$ g++ -o test test.cpp
test.cpp: In function ‘int main(int, char**)’:
test.cpp:18: error: call of overloaded ‘doIt(Both&)’ is ambiguous
test.cpp:7: note: candidates are: void doIt(X)
test.cpp:11: note:                 void doIt(Y)
于 2008-12-22T04:32:37.493 に答える
3

これは を使用した完璧な例ですboost::implicit_cast:

void doIt(X *arg) { }
void doIt(Y *arg) { }

doIt(boost::implicit_cast<X*>(new Both));

他のソリューション (static_cast を含む) とは異なり、 からBoth*への暗黙的な変換X*が不可能な場合、キャストは失敗します。これは、簡単な例で最もよく示されているトリックによって行われます。

X * implicit_conversion(X *b) { return b; }

boost::implicit_castの型を伝えるテンプレートであるというだけですb

于 2008-12-27T06:28:15.447 に答える
2

コンパイラは、オーバーロードを選択するための幅検索ではなく、深さ検索を行います。完全な答えはHerb Sutter の例外的な C++にありますが、残念ながら私はその本を手元に持っていません。

編集:本を手に入れました。これは深さ優先ルールと呼ばれ、「インターフェース原則」と呼ばれます:

クラス X の場合、(a) X を「言及」し、(b) X を「提供」するすべての関数 (フリー関数を含む) は、X のインターフェイスの一部を形成するため、論理的に X の一部です。 .

しかし、 "Koenig Lookup"と呼ばれる二次的なルールがあり、これが事態を難しくしています。

引用:"(簡略化): クラス型 (ここでは A::X 型の x) の関数引数を指定すると、コンパイラは正しい関数名を検索するために、引数の型" -Herb Sutter、例外的な C++、p120

于 2008-12-22T05:48:56.917 に答える
1

引数を x または y に明示的にキャストする必要があります

doIt(新しい両方());

だから追加...

(X *) または (Y *)

お気に入り...

doIt((X *)new Both());

于 2008-12-22T05:07:20.947 に答える
0

私の知る限り、C++コンパイラは、コンパイル時に決定できる最も近くて最も具体的な一致を常に選択します。

ただし、オブジェクトが両方から派生している場合、コンパイラはエラーまたは少なくとも非常に重大な警告を表示する必要があると思います。これは関係のサブタイプに関するものであり、最初のオブジェクトは他のオブジェクトよりも「サブタイプに近い」ものではないため、宣言の順序は重要ではありません。

于 2008-12-22T04:33:51.030 に答える