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

时间:2015-06-04 00:10:15

标签: c++ inheritance pure-virtual

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

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

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

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

我提出的2个解决方案是

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

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

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

3 个答案:

答案 0 :(得分:6)

使用 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();将无效,因为显式限定禁用了虚拟调度。

答案 1 :(得分:2)

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

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

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

这在第33项中描述:&#34;避免隐藏继承的名称&#34;斯科特迈耶斯&#39; &#34;有效的C ++,第三版&#34;。

答案 2 :(得分:1)

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

如果您希望IInterface的{​​{1}}通常在范围func()中使用,则最简单的解决方案是:

MyClass

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

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

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

NB。如果你不知道,纯虚函数也可能有一个正文定义,但这很少在析构函数之外完成。