C++高级编程之——函数重载、内联、缺省参数、隐式转换( 二 )


::Print(…); // 表示 Print 是全局函数而非成员函数
8.1.3 当心隐式类型转换导致重载函数产生二义性
示例 8-1-3 中 , 第一个 output 函数的参数是 int 类型 , 第二个 output 函数的参数是 float 类型 。由于数字本身没有类型 , 将数字当作参数时将自动进行类型转换(称为隐式类型转换) 。语句 output(0.5)将产生编译错误 , 因为编译器不知道该将 0.5 转换成int 还是 float 类型的参数 。隐式类型转换在很多地方可以简化程序的书写 , 但是也可能留下隐患 。
# include <IOStream.h>void output( int x); // 函数声明void output( float x); // 函数声明void output( int x){ cout << " output int " << x << endl ;}void output( float x){ cout << " output float " << x << endl ;}void main(void){ int x = 1; float y = 1.0; output(x); // output int 1 output(y); // output float 1 output(1); // output int 1// output(0.5); // error! ambiguous call, 因为自动类型转换 output(int(0.5)); // output int 0 output(float(0.5)); // output float 0.5}示例 8-1-3 隐式类型转换导致重载函数产生二义性 8.2 成员函数的重载、覆盖与隐藏
成员函数的重载、覆盖(override)与隐藏很容易混淆 , C++程序员必须要搞清楚概念 , 否则错误将防不胜防 。
8.2.1 重载与覆盖
成员函数被重载的特征:
(1)相同的范围(在同一个类中);
(2)函数名字相同;
(3)参数不同;
(4)virtual 关键字可有可无 。
覆盖是指派生类函数覆盖基类函数 , 特征是:
(1)不同的范围(分别位于派生类与基类);
(2)函数名字相同;
(3)参数相同;
(4)基类函数必须有 virtual 关键字 。
示例 8-2-1 中 , 函数 Base::f(int)与 Base::f(float)相互重载 , 而 Base::g(void)
被 Derived::g(void)覆盖 。
#include <iostream.h> class Base{public: void f(int x){ cout << "Base::f(int) " << x << endl; }void f(float x){ cout << "Base::f(float) " << x << endl; } virtual void g(void){ cout << "Base::g(void)" << endl;}}; class Derived : public Base{public: virtual void g(void){ cout << "Derived::g(void)" << endl;}}; void main(void) { Derived d; Base *pb = &d; pb->f(42); // Base::f(int) 42pb->f(3.14f); // Base::f(float) 3.14 pb->g(); // Derived::g(void)}示例 8-2-1 成员函数的重载和覆盖8.2.2 令人迷惑的隐藏规则
本来仅仅区别重载与覆盖并不算困难 , 但是 C++的隐藏规则使问题复杂性陡然增加 。
这里“隐藏”是指派生类的函数屏蔽了与其同名的基类函数 , 规则如下:
(1)如果派生类的函数与基类的函数同名 , 但是参数不同 。此时 , 不论有无 virtual
关键字 , 基类的函数将被隐藏(注意别与重载混淆) 。
(2)如果派生类的函数与基类的函数同名 , 并且参数也相同 , 但是基类函数没有 virtual
关键字 。此时 , 基类的函数被隐藏(注意别与覆盖混淆) 。
示例程序 8-2-2(a)中:
(1)函数 Derived::f(float)覆盖了 Base::f(float) 。
(2)函数 Derived::g(int)隐藏了 Base::g(float) , 而不是重载 。
(3)函数 Derived::h(float)隐藏了 Base::h(float) , 而不是覆盖 。
#include <iostream.h> 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: virtual void f(float x){ cout << "Derived::f(float) " << x << endl; }void g(int x){ cout << "Derived::g(int) " << x << endl; } void h(float x){ cout << "Derived::h(float) " << x << endl; }};示例 8-2-2(a)成员函数的重载、覆盖和隐藏据作者考察 , 很多 C++程序员没有意识到有“隐藏”这回事 。由于认识不够深刻 , 
“隐藏”的发生可谓神出鬼没 , 常常产生令人迷惑的结果 。
示例 8-2-2(b)中 , bp 和 dp 指向同一地址 , 按理说运行结果应该是相同的 , 可事
实并非这样 。
void main(void){Derived d;Base *pb = &d;Derived *pd = &d;// Good : behavior depends solely on type of the objectpb->f(3.14f); // Derived::f(float) 3.14pd->f(3.14f); // Derived::f(float) 3.14// Bad : behavior depends on type of the pointerpb->g(3.14f); // Base::g(float) 3.14pd->g(3.14f); // Derived::g(int) 3 (surprise!)// Bad : behavior depends on type of the pointerpb->h(3.14f); // Base::h(float) 3.14 (surprise!)pd->h(3.14f); // Derived::h(float) 3.14}示例 8-2-2(b) 重载、覆盖和隐藏的比较


推荐阅读