开发者

Resolving ambiguous this pointer in C++

I'm trying to derive a new class from an old one. The base class declaration looks like this:

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

Its constructor looks like this:

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

So when I created my derived class, I first tried to simply inherit from the base class:

class NewDriver : public Driver

and copy the constructor:

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

The compiler (VisualDSP++ 5.0 from Analog Devices) didn't like this:

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

That made sense, so I decided to directly inherit from Plugin and CmdObject. To avoid multiple inheritance ambiguity problems (so I thought), I used virtual inheritance:

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

But then, in the implementation of a virtual method in NewDriver, I tried to call the Mgr::RegisterPlugin method that takes a Plugin*, and I got this:

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

How is the this pointer amb开发者_如何学JAVAiguous, and how do I resolve it?

Thanks,

--Paul


If you derive from Driver, you don't have to call the constructors of Drivers bases explicitly:

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

The constructor of Driver then initializes its own bases, you don't have to and shouldn't do that directly.
If it should behave differently, let it take parameters:

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

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


The golden rule of multiple inheritance -- ALL public bases of ALL classes MUST be virtual. As long as you follow that rule, multiple inheritance will work properly. In your case, you're getting the ambiguous base class errors because Plugin is not declared virtual in Driver


Georg has the correct answer, there is definitely no need to mess with multiple inheritance in this case.

Using multiple inheritance, especially to create the dreaded diamond is strongly discouraged, and will lead to a great deal of confusion and frustration for the vast majority of C++ programmers.


If You create a hierarchy:

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

You can't pass arguments to the A's constructor directly form the C's constructor

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

unless A is a virtual base class of B which is a special case and in this case it is useful. Please check the links provided by Tim Sylvester.

The fact that the compiler mentions this case doesn't mean it's a solution for You.

If You create a hierarchy like in Your code, You have 2 subobjects of type Plugin and 2 subobject of type CmdObject in Your NewDriver object. In this case, if You try to downcast the this pointer of type NewDriver* for example to the type Plugin*, the compiler has no idea how to adjust the address, because it doesn't know to which of the 2 subobjects present in Your NewDriver object that pointer is supposed to point to. That's where the ambiguity mentioned in the error message comes form. There is a way to tell the compiler, but I think the mess I'm describing should convince You already that is not the way.


I'm not certain that introducing Virtual Inheritance is the way you want to go here. The initial error you got was valid - you're trying to invoke the CmdObject() ctor from 'above' the Driver class. Can you add another ctor to the Driver class?


If you had some reason for wanting to inherit from those classes again, then you shouldn't use virtual inheritance. If you want to use virtual inheritance, you need to specify that on the more-base classes. However, you don't want to use virtual inheritance here. Just leave out the initializer of the base classes, since Driver is already doing that. In your example, you don't need a NewDriver constructor at all, and if your implementation actually does need one, then it should only be used to initialize the member variables of NewDriver and it should expect that Driver does the right thing. If Driver does not do the right thing, just give it a constructor that takes appropriate parameters and have that constructor do the right thing. 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!
};


The CmdObject within Driver should be sufficient. Adjust Driver to have a protected constructor which can customize the CmdObject within specified limits.

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" ) {
    ...
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜