当另一个成员存在另一个签名时,调用纯虚拟成员的正确方法是什么?

What is the correct way to call the pure virtual member when another member exists with another signature?

我有一个纯虚拟接口 class 和一个派生的 class 看起来像这样

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

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

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

我想到的 2 个解决方案是

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

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

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

使用 using-declaration:

将基础 class 声明引入派生 class 范围
class MyClass : public IInterface
{
public:
    using IInterface::func;
    void func(int i) { func(); }
};

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

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

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

如果您想避免从基数 class 中隐藏名称,您可以使用 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++, Third Edition" 的第 33 项:"Avoid hiding inherited names" 中有所描述。

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

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

using IInterface::func;

它可以进入 MyClass 的 class 定义(并且会尊重您放置它的访问说明符);或者你只能把它放在func(int i)里面。这样做之后,从 MyClass 范围调用 func 将在 func()func(int) 之间进行重载解析。


static_cast<IInterface*>(this)->func(); 也将起作用:它将为您当前使用的对象调用 func() 的最终覆盖。

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

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