2010-05-11 103 views
3

我試圖從舊的類中派生出新的類。基類的聲明看起來是這樣的:在C++中解析模糊的指針

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; 
} 

編譯器(的VisualDSP ++ 5.0來自Analog Devices)不喜歡這樣的:

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

這很有道理,所以我決定直接從插件和CmdObject繼承。爲了避免多重繼承歧義的問題(所以我認爲),我用虛擬繼承:

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

但隨後,在NewDriver虛擬方法的實現,我試着撥打經理:: RegisterPlugin方法,它接受插件*,我得到了這個:

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

這個指針是如何模糊的,我該如何解決它?

感謝,

--Paul

回答

4

如果從Driver派生,你沒有顯式調用的Driver小號基地的建設者:

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

Driver構造然後初始化自己的基地,你不必,也不應該直接這樣做。
如果它應該表現不同,讓它帶參數:

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

NewDriver::NewDriver() : Driver("NewDriver" /* , ... */) {} 
+3

嚴格地說宣佈virtual,如果基類構造函數不帶任何參數,你甚至不需要把它在初始化列表,因爲它將被默認自動構造。 – 2010-05-11 00:24:59

+0

@dash,這並不完全準確(至少不用g ++)。幾乎繼承的類型將在非虛擬繼承類型之前初始化。因此,如果隱式順序(來自物理繼承層次)與物理順序之間的初始化順序不同,一些編譯器至少會開始發佈有關重新排列初始化順序的警告(即使您省略了初始化列表並允許編譯器做訂單本身)。 – 2010-05-11 00:35:21

+0

我只是稍微改變了措辭,我不想在這裏找到所有其他可能的錯綜複雜。 – 2010-05-11 00:45:13

0

我不能肯定,引入虛擬繼承是你想在這裏走的路。你得到的最初錯誤是有效的 - 你試圖從Driver類的'上方'調用CmdObject()ctor。你可以添加另一個Ctor到Driver類嗎?

1

Georg有正確的答案,在這種情況下肯定不需要混淆多重繼承。

使用multiple inheritance,尤其是創造dreaded diamond強烈勸阻,並會導致混亂和挫折對於絕大多數的C++程序員很大。

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! 
}; 
0

CmdObjectDriver應該足夠了。調整Driver有一個protected構造函數,它可以在指定限制內​​自定義CmdObject

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

...

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

...

NewDriver::NewDriver() : 
    Driver("NewDriver", "MyNewEngine") { 
    ... 
} 
1

如果您創建了一個層次:

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

你不能將參數傳遞給A的構造直接構成C的構造函數

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

除非A是B的虛擬基類,這是一種特殊情況,在這種情況下它是有用的。請檢查Tim Sylvester提供的鏈接。

事實上,編譯器提到這種情況並不意味着它是您的解決方案。

如果您在您的代碼中創建了一個層次結構,那麼您的NewDriver對象中有2個Plugin子對象和2個子對象CmdObject。在這種情況下,如果您嘗試將類型爲NewDriver*this指針向下翻錄爲Plugin*類型,則編譯器不知道如何調整地址,因爲它不知道您的NewDriver對象中存在哪個子對象該指針應該指向。這就是錯誤信息中提到的歧義之處。有一種方法可以告訴編譯器,但我認爲我描述的混亂應該說服你已經不是這樣了。

1

多重繼承的金科玉律 - ALLMUST的ALL公共基礎是虛擬的。只要你遵循這個規則,多重繼承就可以正常工作。在你的情況,你得到的曖昧基類錯誤,因爲PluginDriver