4

古いクラスから新しいクラスを派生させようとしています。基本クラスの宣言は次のようになります。

class Driver : public Plugin, public CmdObject
{
protected:
    Driver();

public:
    static Driver* GetInstance();
    virtual Engine& GetEngine();
public:
    // Plugin methods...
    virtual bool InitPlugin (Mgr* pMgr);
    virtual bool Open();
    virtual bool Close();

    // CmdObject
    virtual bool ExecObjCmd(uint16 cmdID, uint16 nbParams, CommandParam *pParams, CmdChannelError& error);

    Mgr *m_pMgr;

protected:
    Services *m_pServices;
    Engine m_Engine;
};

そのコンストラクタは次のようになります。

Driver::Driver() : 
    YCmdObject("Driver", (CmdObjectType)100, true),
    m_Engine("MyEngine")
{
    Services *m_pServices = NULL;
    Mgr *m_pMgr = NULL;
}

したがって、派生クラスを作成したとき、最初に基本クラスから単純に継承しようとしました。

class NewDriver : public Driver

コンストラクターをコピーします。

NewDriver::NewDriver() : 
    CmdObject("NewDriver", (EYCmdObjectType)100, true),
    m_Engine("MyNewEngine")
{
    Services *m_pServices = NULL;
    Mgr *m_pMgr = NULL;
}

コンパイラ (Analog Devices の VisualDSP++ 5.0) はこれを気に入らなかった:

".\NewDriver.cpp", line 10: cc0293:  error: indirect nonvirtual base
      class is not allowed
 CmdObject("NewDriver", (EYCmdObjectType)100, true),

これは理にかなっていたので、Plugin と CmdObject から直接継承することにしました。複数の継承のあいまいさの問題を回避するために (そう思ったので)、仮想継承を使用しました。

class NewDriver : public Driver, public virtual Plugin, public virtual CmdObject

しかし、NewDriver の仮想メソッドの実装で、Plugin* を受け取る Mgr::RegisterPlugin メソッドを呼び出そうとしたところ、次のようになりました。

".\NewDriver.cpp", line 89: cc0286:  error: base class "Plugin" is
      ambiguous
 if (!m_pMgr->RegisterPlugin(this))

this ポインターはどのようにあいまいで、どうすれば解決できますか?

ありがとう、

――ポール

4

7 に答える 7

4

から派生する場合、 s ベースDriverのコンストラクターを明示的に呼び出す必要はありません。Driver

class NewDriver : public Driver { /* ... */ };
NewDriver::NewDriver() : Driver() {}

thenのコンストラクターはDriver、独自のベースを初期化します。これを直接行う必要はなく、行うべきではありません。
異なる動作をする必要がある場合は、パラメーターを取ります。

class Driver : /* ... */ {
public:
    Driver(const std::string& name /* , ... */)
      : CmdObject(name /* , ... */)
    {}
    // ...
};

NewDriver::NewDriver() : Driver("NewDriver" /* , ... */) {}
于 2010-05-11T00:17:26.730 に答える
2

多重継承の黄金律 --すべてのクラスのすべてのパブリック ベースは仮想でなければなりません。そのルールに従っている限り、多重継承は適切に機能します。あなたの場合、でPlugin宣言されていないvirtualため、あいまいな基本クラスのエラーが発生していますDriver

于 2010-05-11T01:15:25.007 に答える
1

Georg は正しい答えを持っています。この場合、多重継承をいじる必要はまったくありません。

特に恐ろしいひし形を作成するために多重継承を使用することは強く推奨されておらず、大多数の C++ プログラマーに多大な混乱とフラストレーションをもたらすことになります。

于 2010-05-11T00:24:49.857 に答える
1

階層を作成する場合:

class A {public:  a(int i){} };
class B : public A {public:  b(){} };
class C : public B {public:  c(); };

C のコンストラクターから直接 A のコンストラクターに引数を渡すことはできません。

C::C() : A(5) {} // illegal

A が B の仮想基本クラスでない限り、これは特殊なケースであり、この場合は便利です。Tim Sylvester が提供するリンクを確認してください。

コンパイラがこのケースに言及しているという事実は、それがあなたにとっての解決策であることを意味するものではありません。

コードのように階層を作成すると、オブジェクトに 2 つのタイプのPluginサブオブジェクトと 2 つのタイプのCmdObjectサブオブジェクトがありNewDriverます。この場合、たとえばtype のthisポインタを typeにダウンキャストしようとすると、コンパイラはアドレスを調整する方法がわかりません。これは、オブジェクトに存在する 2 つのサブオブジェクトのどちらにポインタが想定されているかがわからないためです。を指します。ここで、エラー メッセージに記載されているあいまいさが生じます。コンパイラに伝える方法はありますが、私が説明している混乱から、それはその方法ではないことをすでにあなたに納得させるはずです。NewDriver*Plugin*NewDriver

于 2010-05-11T00:39:35.147 に答える
0

Virtual Inheritance の導入が、あなたがここに行きたい方法であるかどうかはわかりません。あなたが得た最初のエラーは有効でした - Driver クラスの「上」から CmdObject() ctor を呼び出そうとしています。Driver クラスに別の ctor を追加できますか?

于 2010-05-11T00:18:18.280 に答える
0

これらのクラスから再度継承したい何らかの理由がある場合は、仮想継承を使用しないでください。仮想継承を使用する場合は、より基本的なクラスで指定する必要があります。ただし、ここでは仮想継承を使用したくありません。基本クラスのイニシャライザは省略してください。Driver はすでにそれを行っているからです。あなたの例では、NewDriver コンストラクターはまったく必要ありません。実際に実装が必要な場合は、NewDriver のメンバー変数を初期化するためにのみ使用し、Driver が正しいことを行うことを期待する必要があります。Driver が正しいことをしない場合は、適切なパラメーターを受け取るコンストラクターを与えて、そのコンストラクターに正しいことをさせるだけです。例えば

class Driver : public Stuff
{
public:
    Driver(const char* enginename) : Stuff(99), m_Engine(enginename) { }

private:
   Engine m_Engine;
};

class NewDriver : public Driver
{
public:
   NewDriver() : Driver("New Driver!") { } // yes, Stuff gets initialized with 99 automatically!
};
于 2010-05-11T00:29:32.337 に答える
0

CmdObjectDriverで十分なはずです。指定された制限内でカスタマイズできるコンストラクターDriverを持つように調整します。protectedCmdObject

class Driver ...
protected:
    Driver( std::string driverName, std::string engineName );

…</p>

Driver::Driver( std::string driverName, std::string engineName ) :
    YCmdObject(driverName, (CmdObjectType)100, true),
    m_Engine(engineName) {

…</p>

NewDriver::NewDriver() : 
    Driver( "NewDriver", "MyNewEngine" ) {
    ...
}
于 2010-05-11T00:30:55.367 に答える