【问题标题】:What is the correct way to call the pure virtual member when another member exists with another signature?当另一个成员存在另一个签名时,调用纯虚拟成员的正确方法是什么?
【发布时间】:2015-08-18 10:03:33
【问题描述】:

我有一个像这样的纯虚拟接口类和派生类

class IInterface
{
public:
    virtual void func() = 0;
};

class MyClass : public IInterface
{
public:
    void func(int i) { func(); }
};

编译器抱怨在func(int i) 中对func() 的调用不接受0 个参数。指定调用纯虚拟成员的正确方法是什么?

我想出的两个解决方案是

void func(int i) { static_cast<IInterface*>(this)->func(); }

void func(int i) { IInterface::func(); }

这些都可行吗?有没有更好的办法?两者看起来都很笨重。

【问题讨论】:

  • 您的第二个解决方案是正确的方法。
  • 为什么要实际调用纯虚方法?
  • void dontHideBaseMembers(int i) { func(); }
  • 在您的编辑中,您没有在 MyClass 中包含 func() 的正文,因此无论如何它都不会构建。一旦你这样做了,它仍然不起作用吗?如果funcMyClass 中定义为无参数重载,它应该可以编译并解决您的问题。
  • @VoidStar 如果 OP 在 MyClass 中定义 func() 他可以直接调用它,不需要任何马戏团

标签: c++ inheritance pure-virtual


【解决方案1】:

使用using-declaration将基类声明带入派生类范围:

class MyClass : public IInterface
{
public:
    using IInterface::func;
    void func(int i) { func(); }
};

或者,将 this 转换为指向 base 的指针也可以(即您的第一个选项):

void func(int i) { static_cast<IInterface*>(this)->func(); }

IInterface::func(); 不起作用,因为显式限定会禁用虚拟调度。

【讨论】:

  • 这很丑,但它必须这样做。我觉得奇怪的是语言需要这个,但是当函数在同一个类中时没有歧义
  • @cppguy 在作用域中声明的 C++ 名称中隐藏与先前作用域中相同的名称;它类似于int x = 4; { int x; x = 5; } cout &lt;&lt; x; 让你4
【解决方案2】:

如果您想避免对基类隐藏名称,可以使用using 语句:

class MyClass : public IInterface
{
public:
    using IInterface::func;      // prevents `func()` from being hidden by `func(int)`

    void func(int i) { func(); }
};

这在 Scott Meyers 的“Effective C++,第三版”的第 33 条:“避免隐藏继承的名称”中有所描述。

【讨论】:

    【解决方案3】:

    代码void func(int i) { func(); } 不起作用,因为当您在MyClass 的范围内声明func 时,该名称隐藏了基类中称为func 的任何其他名称。

    如果您希望IInterfacefunc()MyClass 范围内普遍可用,最简单的解决方案是:

    using IInterface::func;
    

    它可以放在 MyClass 的类定义中(并且会尊重您放置它的访问说明符);或者你只能把它放在func(int i)里面。完成此操作后,从MyClass 范围内调用func 将在func()func(int) 之间进行重载解析。


    static_cast&lt;IInterface*&gt;(this)-&gt;func(); 也可以工作:它将为您当前正在使用的对象调用func() 的最终覆盖器。

    版本IInterface::func()不做虚拟调度;它实际上调用了特定的函数IInterface::func。如果您没有定义这样的函数,那么您将导致未定义的行为;这可能会显示为链接器错误,或有关尝试调用纯虚函数的运行时错误。

    注意。如果您不知道,纯虚函数也可能定义了一个主体,但这很少在析构函数之外完成。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-03-31
      • 2019-02-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多