在C ++中解决模糊的this指针

时间:2010-05-11 00:13:22

标签: c++ multiple-inheritance virtual-inheritance

我正试图从一个旧类中派生出一个新类。基类声明如下所示:

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

编译器(ADI公司的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中实现虚拟方法时,我尝试调用带有插件*的Mgr :: RegisterPlugin方法,我得到了这个:

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

这个指针有多么模糊,如何解决?

谢谢,

- 保

7 个答案:

答案 0 :(得分: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" /* , ... */) {}

答案 1 :(得分:2)

多重继承的黄金法则 - 所有类的 ALL 公共基础必须是虚拟的。只要遵循该规则,多重继承就能正常工作。在您的情况下,您会收到不明确的基类错误,因为Plugin中未声明virtual Driver

答案 2 :(得分:1)

Georg有正确的答案,在这种情况下绝对不需要混淆多重继承。

使用multiple inheritance,尤其是创建dreaded diamond 强烈不鼓励,并且会给绝大多数C ++程序员带来很多困惑和挫折。< / p>

答案 3 :(得分: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提供的链接。

编译器提到这种情况的事实并不意味着它是你的解决方案。

如果您在代码中创建了一个层次结构,则在Plugin对象中有2个类型为CmdObject的子对象和2个类型为NewDriver的子对象。在这种情况下,如果您尝试将类型为this的{​​{1}}指针向下转换为类型NewDriver*,则编译器不知道如何调整地址,因为它不会知道指针应该指向你的Plugin*对象中的2个子对象中的哪一个。这就是错误消息中提到的含糊不清的地方。有一种方法可以告诉编译器,但我认为我所描述的混乱应该说服你已经不是那样了。

答案 4 :(得分:0)

我不确定引入虚拟继承是你想要去的方式。你得到的初始错误是有效的 - 你试图从Driver类的“上方”调用CmdObject()ctor。你可以在Driver类中添加另一个ctor吗?

答案 5 :(得分:0)

如果您有某种理由希望再次从这些类继承,那么您不应该使用虚拟继承。如果要使用虚拟继承,则需要在更多基类上指定。但是,您不希望在此处使用虚拟继承。只需省略基类的初始化程序,因为Driver已经这样做了。在您的示例中,您根本不需要NewDriver构造函数,如果您的实现确实需要一个,那么它应用于初始化NewDriver的成员变量,它应该期望该驱动程序做对了。如果Driver没有做正确的事情,只需给它一个构造函数,该构造函数接受适当的参数并让构造函数做正确的事情。 E.g。

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

答案 6 :(得分:0)

CmdObject内的Driver就足够了。调整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" ) {
    ...
}