Разрешить неоднозначно этот указатель в C ++ - PullRequest
4 голосов
/ 11 мая 2010

Я пытаюсь вывести новый класс из старого. Объявление базового класса выглядит так:

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),

Это имело смысл, поэтому я решил напрямую наследовать от Plugin и CmdObject. Чтобы избежать проблем неоднозначности множественного наследования (как я думал), я использовал виртуальное наследование:

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

Но затем, при реализации виртуального метода в NewDriver, я попытался вызвать метод Mgr :: RegisterPlugin, который принимает Plugin *, и я получил это:

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

Как этот указатель неоднозначен, и как мне его разрешить?

Спасибо

- Пол

Ответы [ 7 ]

4 голосов
/ 11 мая 2010

Если вы наследуете от Driver, вам не нужно явно вызывать конструкторы Driver s баз:

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

Конструктор Driver затем инициализирует свои собственные базы, вам не нужно и не следует делать это напрямую.
Если он должен вести себя по-другому, пусть он принимает параметры:

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

NewDriver::NewDriver() : Driver("NewDriver" /* , ... */) {}
2 голосов
/ 11 мая 2010

Золотое правило множественного наследования - ALL открытые базы ALL классов ДОЛЖНЫ быть виртуальными. Пока вы следуете этому правилу, множественное наследование будет работать правильно. В вашем случае вы получаете неоднозначные ошибки базового класса, потому что Plugin не объявлено virtual в Driver

1 голос
/ 11 мая 2010

Если вы создаете иерархию:

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, который является частным случаем и в этом случае он полезен. Пожалуйста, проверьте ссылки, предоставленные Тимом Сильвестром.

Тот факт, что компилятор упоминает этот случай, не означает, что это решение для Вас.

Если вы создаете иерархию, как в вашем коде, у вас есть 2 подобъекта типа Plugin и 2 подобъекта типа CmdObject в вашем NewDriver объекте. В этом случае, если вы попытаетесь уменьшить указатель this типа NewDriver*, например, на тип Plugin*, компилятор не будет знать, как настроить адрес, потому что он не знает, какой из 2 подобъекты, присутствующие в вашем NewDriver объекте, на который должен указывать указатель. Вот где появляется двусмысленность, упомянутая в сообщении об ошибке. Есть способ сообщить компилятору, но я думаю, что описанный мною беспорядок должен убедить Вас, что это не тот путь.

1 голос
/ 11 мая 2010

У Георга правильный ответ, в этом случае определенно нет необходимости возиться с множественным наследованием.

Использование множественного наследования , особенно для создания страшного алмаза * сильно обескураживает, и приведет к большой путанице и разочарованию для подавляющего большинства программистов на C ++.

0 голосов
/ 11 мая 2010

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" ) {
    ...
}
0 голосов
/ 11 мая 2010

Если у вас была причина желать наследовать от этих классов снова, вам не следует использовать виртуальное наследование.Если вы хотите использовать виртуальное наследование, вам нужно указать это в более базовых классах.Однако вы не хотите использовать виртуальное наследование здесь.Просто оставьте инициализатор базовых классов, так как Driver уже делает это.В вашем примере вам вообще не нужен конструктор NewDriver, и если вашей реализации он действительно нужен, то для инициализации переменных-членов NewDriver следует использовать only , и следует ожидать, что 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 голосов
/ 11 мая 2010

Я не уверен, что введение виртуального наследования - это то, что вам нужно. Первоначальная ошибка, которую вы получили, была допустимой - вы пытаетесь вызвать Ctor CmdObject () из «класса» Driver. Можете ли вы добавить еще один ctor в класс Driver?

...