当另一个成员存在另一个签名时,调用纯虚拟成员的正确方法是什么?
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.
如果您希望 IInterface
的 func()
在 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
。如果您没有定义这样的函数,那么您将导致未定义的行为;这可能会显示为链接器错误,或有关尝试调用纯虚函数的运行时错误。
注意。如果您不知道,纯虚函数也可能定义了一个函数体,但这很少在析构函数之外完成。
我有一个纯虚拟接口 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.
如果您希望 IInterface
的 func()
在 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
。如果您没有定义这样的函数,那么您将导致未定义的行为;这可能会显示为链接器错误,或有关尝试调用纯虚函数的运行时错误。
注意。如果您不知道,纯虚函数也可能定义了一个函数体,但这很少在析构函数之外完成。