11

gcc 3.4.5(mingw)を使用すると、クラスの1つで次のコンパイルエラーが発生します。

src/ModelTester/CModelTesterGui.cpp:1308: error: request for member `addListener' is ambiguous
include/utility/ISource.h:26: error: candidates are: void utility::ISource<T>::addListener(utility::IListener<T>*) [with T = const SConsolePacket&]
include/utility/ISource.h:26: error:                 void utility::ISource<T>::addListener(utility::IListener<T>*) [with T = const SControlPacket&]

うまくいけば、それISource<T>は、オブジェクトが何らかの一致するタイプのオブジェクトのインフォーマーである可能性があることを示すテンプレートインターフェイスであることがわかりますIListener<T>。ですから、私がイライラしたのは、私が知る限り、関数があいまいであるのに、何らかの理由で関数があいまいであるという考えです。addListener()メソッドは、さまざまな入力タイプおよびに対してオーバーロードされIListener<const SConsolePacket&>ますIListener<const SControlPacket&>。使用法は次のとおりです。

m_controller->addListener( m_model );

オブジェクトm_modelへのポインタはどこにあり、からのみ継承し、からは絶対に継承しませんIRigidBodyIRigidBodyIListener< const SControlPacket& >IListener< const SConsolePacket& >

健全性チェックとして、私はdoxygenを使用してクラス階層図を生成しましたが、doxygenはIRigidBodyIListener< const SConsolePacket& >

明らかに、C++での継承についての私の理解は正確には正しくありません。とは2つの異なるタイプであり、関数宣言IListener<const SControlPacket&>IListener<const SConsolePacket&>

addListener(IListener<const SConsolePacket&>* listener)

addListener(IListener<const SControlPacket&>* listener)

入力されたパラメーターの(別個の)異なるタイプに応じて、2つの別個のことを実行する2つの別個の関数を宣言します。IRigidBodyさらに、anへのポインターはanへのポインターでもあり、コンパイラーをIListener<const SControlPacket&>呼び出すことaddListener( m_model )により、上記の2つの関数の2番目を呼び出していることを理解する必要があるという印象を受けています。

私もこのようにキャストしてみm_modelました:

m_controller->addListener(
        static_cast<IListener<const SControlPacket&>*>(m_model) );

しかし、それでもそのエラーが発生します。私は、これらの機能がどのように曖昧であるかを一生見ることができません。誰かがこの問題に光を当てることができますか?

PS私はこれを行うことによって関数を明確にする方法を知っています:

m_controller->ISource<const SControlPacket&>::addListener( m_model );

たまたまそれはひどく読めないと思っていたので、そうする必要はありません。

編集...冗談です。リンカエラーが発生するため、問題は解決しないようです。

CModelTesterGui.cpp:1312: undefined reference to `utility::ISource<aerobat::SControlPacket const&>::addListener(utility::IListener<SControlPacket const&>*)'
4

1 に答える 1

29

あなたの状況は次のように見えます:

struct A {
  void f();
};

struct B {
  void f(int);
};

struct C : A, B { };

int main() { 
  C c; 
  c.B::f(1); // not ambiguous
  c.f(1);    // ambiguous
}

fの2番目の呼び出しはあいまいです。名前を検索すると、2つの異なる基本クラススコープ内の関数が見つかるためです。この状況では、ルックアップはあいまいです-それらは互いに過負荷になりません。修正は、メンバー名ごとにusing宣言を使用することです。ルックアップはスコープ内の名前を検索し、Cそれ以上ルックアップしません。

struct C : A, B { using A::f; using B::f; };

これで、呼び出しは2つの関数を見つけ、過負荷解決を実行し、1つの関数intが適合することを見つけます。コードに引き継がれると、次のようなことをしなければならないことを意味します

struct controller : ISource<const SConsolePacket&>, ISource<const SControlPacket&> {
  using ISource<const SConsolePacket&>::addListener;
  using ISource<const SControlPacket&>::addListener;
};

これで、2つの名前は同じスコープ内にあり、互いにオーバーロードできるようになりました。ルックアップはコントローラークラスで停止し、2つの基本クラスブランチにさらに飛び込むことはありません。

于 2009-08-21T17:12:25.207 に答える