覆盖重载方法隐藏了一些重载
Overriding overloaded methods hides some of the overloads
假设我有以下 classes:
class Base
{
public:
virtual void myMethod()
{
}
virtual void myMethod(int x)
{
}
};
class Derived : public Base
{
};
在这种情况下,以下代码可以正常编译。
int main(void)
{
Derived obj;
obj.myMethod();
return (0);
}
当我尝试像下面那样覆盖 myMethod
之一时出现问题。
class Derived : public Base
{
public:
virtual void myMethod(int x)
{
}
};
现在代码无法编译并给出错误:
error C2660: 'Derived::myMethod' : function does not take 0 arguments
我已经覆盖了一个重载函数,显然这已经从 Derived
class 中隐藏了另一个。为了摆脱错误,我必须覆盖所有重载。这违背了我的预期,对我来说似乎不合理。为什么这段代码会这样?
问题可以重现here。
您的编译器 100% 正确。
你重载了你的函数以将一个整数作为参数,然后这个函数隐藏了所有基本 class 函数 - 所以 obj 调用 myMethod(int)
是默认的,但你没有为你的函数提供一个整数。
如果您将代码修复为
obj.myMethod(4);
问题解决了。
在派生 class 中覆盖函数时 - 它隐藏了所有其他基础 class 重载。仍然可以使用以下语法调用基础 class :
obj.Base::myMethod();
在更深入的回答中,这就是它发生的原因。
首先,我们需要了解编译器如何编译面向对象的代码。请记住 - 函数编译成汇编命令,它们位于 code segment
中。变量编译成位于堆栈、堆或数据段中的内存行。函数位于应用程序的一部分,变量位于完全不同的区域。编译器如何编译带有变量和函数的 class?好吧,它没有。这个想法是这样的:
假设有一个名为 X 的 class,带有一些变量和一些函数
1) 取出所有成员函数,将它们带出class
2) 向每个现在全局声明的函数添加另一个参数 - const X* this
3) 每次看到语法 x.someFunc(args..)
将其更改为 someFunc(args..,&x)
4) 在函数中 - 如果你不认识一个符号 - 尝试附加一个 this->
看看你是否可以编译这个
5) 将 X 编译为 C 结构,将另一个编译为 C 函数
6) 对派生的 classes 做同样的事情
(当然,还有虚拟 table 问题,但我们就此打住)
在你的例子中:
可能代表编译器解析代码的伪代码是
struct Base{}
struct Derived{}
void myMethod(const Base* this);
void myMethod(int x,const Base* this);
void myMethod(int x, const Derived* this);
//what you tried to do is :
myMethod (&obj);
但是编译器找不到任何与这些参数相匹配的函数!
对于最初不知道面向对象如何编译的人来说,这不是很直观,但是在理解了这个编译过程之后,它就更有意义了。
事实上,在一个作用域中声明一个函数会在更广泛的作用域中隐藏任何同名的东西,所以你在派生 class 中的重写隐藏了基础 class 中的重载。
这通常不是问题,因为您通常会通过基础 class 与多态 classes 进行交互;通常是您想要的,因为它可以防止对基 class 的更改意外更改与派生 class 交互的代码的行为。
但如果需要,您可以轻松地将其带回派生 class 的范围:
using Base::myMethod;
或通过限定名称引用函数:
obj.Base::myMethod();
通过覆盖 Derived class 中的函数,您隐藏了 Base class.
中存在的该函数名称的所有重载实现
因此,用 void Derived::myMethod(int)
覆盖 void Base::myMethod(int)
只会为 void Derived::myMethod(int)
生成代码,而不会为 void Derived::myMethod()
.
生成代码
如前所述,您可以显式调用 Base 的函数:
obj.Base::myMethod()
.
假设我有以下 classes:
class Base
{
public:
virtual void myMethod()
{
}
virtual void myMethod(int x)
{
}
};
class Derived : public Base
{
};
在这种情况下,以下代码可以正常编译。
int main(void)
{
Derived obj;
obj.myMethod();
return (0);
}
当我尝试像下面那样覆盖 myMethod
之一时出现问题。
class Derived : public Base
{
public:
virtual void myMethod(int x)
{
}
};
现在代码无法编译并给出错误:
error C2660: 'Derived::myMethod' : function does not take 0 arguments
我已经覆盖了一个重载函数,显然这已经从 Derived
class 中隐藏了另一个。为了摆脱错误,我必须覆盖所有重载。这违背了我的预期,对我来说似乎不合理。为什么这段代码会这样?
问题可以重现here。
您的编译器 100% 正确。
你重载了你的函数以将一个整数作为参数,然后这个函数隐藏了所有基本 class 函数 - 所以 obj 调用 myMethod(int)
是默认的,但你没有为你的函数提供一个整数。
如果您将代码修复为
obj.myMethod(4);
问题解决了。
在派生 class 中覆盖函数时 - 它隐藏了所有其他基础 class 重载。仍然可以使用以下语法调用基础 class :
obj.Base::myMethod();
在更深入的回答中,这就是它发生的原因。
首先,我们需要了解编译器如何编译面向对象的代码。请记住 - 函数编译成汇编命令,它们位于 code segment
中。变量编译成位于堆栈、堆或数据段中的内存行。函数位于应用程序的一部分,变量位于完全不同的区域。编译器如何编译带有变量和函数的 class?好吧,它没有。这个想法是这样的:
假设有一个名为 X 的 class,带有一些变量和一些函数
1) 取出所有成员函数,将它们带出class
2) 向每个现在全局声明的函数添加另一个参数 - const X* this
3) 每次看到语法 x.someFunc(args..)
将其更改为 someFunc(args..,&x)
4) 在函数中 - 如果你不认识一个符号 - 尝试附加一个 this->
看看你是否可以编译这个
5) 将 X 编译为 C 结构,将另一个编译为 C 函数
6) 对派生的 classes 做同样的事情
(当然,还有虚拟 table 问题,但我们就此打住)
在你的例子中:
可能代表编译器解析代码的伪代码是
struct Base{}
struct Derived{}
void myMethod(const Base* this);
void myMethod(int x,const Base* this);
void myMethod(int x, const Derived* this);
//what you tried to do is :
myMethod (&obj);
但是编译器找不到任何与这些参数相匹配的函数! 对于最初不知道面向对象如何编译的人来说,这不是很直观,但是在理解了这个编译过程之后,它就更有意义了。
事实上,在一个作用域中声明一个函数会在更广泛的作用域中隐藏任何同名的东西,所以你在派生 class 中的重写隐藏了基础 class 中的重载。
这通常不是问题,因为您通常会通过基础 class 与多态 classes 进行交互;通常是您想要的,因为它可以防止对基 class 的更改意外更改与派生 class 交互的代码的行为。
但如果需要,您可以轻松地将其带回派生 class 的范围:
using Base::myMethod;
或通过限定名称引用函数:
obj.Base::myMethod();
通过覆盖 Derived class 中的函数,您隐藏了 Base class.
中存在的该函数名称的所有重载实现因此,用 void Derived::myMethod(int)
覆盖 void Base::myMethod(int)
只会为 void Derived::myMethod(int)
生成代码,而不会为 void Derived::myMethod()
.
如前所述,您可以显式调用 Base 的函数:
obj.Base::myMethod()
.