解决 C++ 中不明确的 this 指针

发布于 2024-08-31 16:11:33 字数 1756 浏览 3 评论 0原文

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

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 指针如何不明确,如何解决?

谢谢,

--保罗

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 ambiguous, and how do I resolve it?

Thanks,

--Paul

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

伴梦长久 2024-09-07 16:11:33

如果您从 Driver 派生,则不必显式调用 Driver 基类的构造函数:

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

Driver 的构造函数然后初始化其自己的构造函数基地,你不必也不应该直接这样做。
如果它的行为不同,请让它接受参数:

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

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

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" /* , ... */) {}
谁的年少不轻狂 2024-09-07 16:11:33

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

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

悲凉≈ 2024-09-07 16:11:33

Georg 的答案是正确的,在这种情况下绝对没有必要搞乱多重继承。

使用多重继承,尤其是创建可怕的钻石强烈< /strong> 气馁,并且会给绝大多数 C++ 程序员带来很大的困惑和沮丧。

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.

流云如水 2024-09-07 16:11:33

如果您创建层次结构:

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 的虚拟基类,这是一种特殊情况,在这种情况下它很有用。请检查蒂姆·西尔维斯特提供的链接。

编译器提到这种情况并不意味着它是适合您的解决方案。

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

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.

情徒 2024-09-07 16:11:33

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

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?

御守 2024-09-07 16:11:33

如果您出于某种原因想要再次从这些类继承,那么您不应该使用虚拟继承。如果要使用虚拟继承,则需要在更基类上指定。但是,您不想在这里使用虚拟继承。只需省略基类的初始化程序,因为 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!
};

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!
};
烟火散人牵绊 2024-09-07 16:11:33

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

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" ) {
    ...
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文