1.成员函数的重载、覆盖与隐藏
成员函数的重载、覆盖(override)与隐藏很容易混淆,C++程序员必须要搞清楚概念,否则错误将防不胜防。
1.1重载与覆盖
成员函数被重载的特征:
(1)相同的范围(在同一个类中)
(2)函数名字相同
(3)参数不同
(4)virtual关键字可有可无
覆盖是指派生类函数覆盖基类函数,特征是:
(1)不同的范围(分别位于派生类与基类)
(2)函数名字相同
(3)参数形同
(4)基类函数必须有virtual关键字
示例中,函数Base::f(int)与Base::f(float)相互重载,而Base::g(void)被Derived::g(void)覆盖。
-
#include <iostream>
-
using namespace std;
-
-
class Base
-
{
-
public:
-
//f(int) and f(float) is overload function
-
void f(int x)
-
{
-
cout << "Base::f(int)" << endl;
-
}
-
-
void f(float x)
-
{
-
cout << "Base::f(float)" << endl;
-
}
-
//virtual override
-
virtual void g(void)
-
{
-
cout << "Base::g(void)" << endl;
-
}
-
-
};
-
class Derived : public Base
-
{
-
public:
-
virtual void g(void)
-
{
-
cout << "Derived::g(void)" << endl;
-
}
-
};
-
-
int main()
-
{
-
Derived d;
-
Base *pb = &d;
-
-
pb->f(42); //Base::f(int)
-
pb->f(3.14f); //Base::f(float)
-
pb->g(); //Derived::g();
-
-
return 0;
-
}
1.2令人迷惑的隐藏规则
本来仅仅区别重载与覆盖并不算困难,但是C++的隐藏规则使问题复杂性陡然增加。这里“隐藏”是指派生类的函数屏蔽了与其同名的基类函数,规则如下:
(1)如果派生类的函数与基类的函数同名, 但参数不同,此时,不论有无virtual关键字,基类的函数将被隐藏(注意b别与重载混淆)
(2)如果派生类的函数与基类的函数同名, 并且参数也相同, 但是基类的函数没有virtual关键字。此时,基类的函数将被隐藏(注意别与覆盖混淆)
示例程序(a)中:
(1)函数Derived::f(float)覆盖了Base::f(float)。
(2)函数Derived::g(int)隐藏了Base::g(float),而不是重载。
(3)函数Derived::h(float)隐藏了Base::h(float),而不是覆盖。
-
#include <iostream>
-
using namespace std;
-
-
class Base
-
{
-
public:
-
virtual void f(float x)
-
{
-
cout << "Base::f(float) " << x << endl;
-
}
-
-
void g(float x)
-
{
-
cout << "Base::g(float) " << x << endl;
-
}
-
-
void h(float x)
-
{
-
cout << "Base::h(float) " << x << endl;
-
}
-
};
-
class Derived : public Base
-
{
-
public:
-
//override
-
virtual void f(float x)
-
{
-
cout << "Derived::f(flaot) " << x << endl;
-
}
-
-
//hidden
-
void g(int x)
-
{
-
cout << "Derived::g(int) " << x << endl;
-
}
-
-
//hidden
-
void h(float x)
-
{
-
cout << "Derived::h(float) " << x << endl;
-
}
-
};
-
int main()
-
{
-
Derived d;
-
Base *pb = &d;
-
Derived *pd = &d;
-
-
pb->f(3.14f); //Derived::f(float)
-
pd->f(3.14f); //Derived::f(float)
-
-
-
pb->g(3.14f); //Base::g(float)
-
pd->g(3.14f); //Derived::g(int)
-
-
pb->h(3.14f); //Base::h(float)
-
pd->h(3.14f); //Derived::h(float)
-
return 0;
-
}
但是隐藏规则至少有两个存在的理由:
(1)写语句pd->f(10)的人可能真的想调用Derived::f(char *)函数,只是他误将参数写错了。有了隐藏规则,编译器就可以明确指出错误,这未必不是好事。否则,编译器会静悄悄地将错就错,程序员将很难发现这个错误,流下祸根。
(2)假如类Derived有多个基类(多重继承),有时搞不清楚哪些基类定义了函数f。如果没有隐藏规则,那么pd->f(10)可能会调用一个出乎意料的基类函数f。尽管隐藏规则看起来不怎么有道理,但它的确能消灭这些意外。
阅读(1718) | 评论(0) | 转发(0) |