24.在函数重载和设定參数缺省值间要谨慎选择。
获得一种类型的数据的最小值或最大值,对于c中,一般使用在<linits.h>中定义的各种宏如INT_MIN 来进行表示,可是这样无法进行泛型编程。即相应怎样一种类型T返回相应类型的最小或最大值。
而在c++中一般如此获得
std::numeric_limits<T>::min()c++在<limits>中定义了类模版numeric_limits,用来返回相应类型的最小最大值。这是一个非常实用的东西。
然后继续讨论函数重载与參数缺省值,例如以下面情况:
int fun(){ return 1; } int fun(int a){ return a; } int fun(int a=1,int b = 0){ return a+b; }对于第3个函数,当没有參数和仅仅有一个參数时会与前两个函数冲突,可是对于第三个函数,即有默认值的情况下。其能直接具有所有三个函数的功能。使用默认值的函数其效果更好且功能很多其它。
可是有时找不到一个好的缺省值。当对5个以内的值求和时,能够设每一个參数的默认值为0,可是当对5个以内的值进行求平均数时,要获得传入參数的个数,无法通过函数的參数来实现,所以仅仅能重载5个函数,即仅仅有一个,两个,3。4,5个函数的全部情况。
还有一种必须使用重载函数的情况是:想完毕一项特殊的任务,但算法取决于给定的输入值。就是说函数因为输入參数不同进行操作不同的这类函数要重载,如类的构造函数。
25.避免对指针和数字类型的重载。
如函数 void f(int x);和void f(int * p);这两个函数的。重载是会出错。简单来说对于实參为0,即0是什么?0即是指针有是int。但其实在编译器中执行
void f(int* x){ cout<<"int_ptr"<<endl; } void f(int x){ cout<<"int"<<endl; } int main(){ f(NULL);
结果为 输出 int ,即0是一个int。人们觉得一个调用具有多义性时,编译器却不这么干。
NULL的类型是就是int,要使其调用 f(int*)这个函数,就必须如此做
f(static_cast<int*>(NULL));可是假设将NULL定义为UL。即无符号整数
#define NULL 0UL在调用f(NULL)又会报错。重载不明白,NULL即能够是int也能够是int*
可是假设又将f(int)函数改为
void f(unsigned long x)。又会正确,由于NULL是unsigned long。而f函数中參数也是。
而假设我们须要一个不论什么地方都能够使用的随意类型的NULL指针。就必须设计一个产生NULL指针对象的类:
#ifdef NULL #undef NULL #endif class NullClass{ public: template<class T> //模版 operator T*()const{return 0;}//返回一个T*的null指针。然后再次使用 f(NULL)的时候,就会调用隐式的类型转换,获得一个对象T类型的null指针。可是这样还不够。改进:}; const NullClass NULL;//NULL的常量
首先我们仅仅须要一个NullClass对象,所以给这个类一个名字是没有必要的,定义一个匿名类并使NULL成为这样的类型。
其次。我们想让NULL可以转换为怎样类型的指针。那就要可以处理成员指针(指 指向类中函数的指针),要再定义一个成员模版,将类C与全部类型T转换为类型 T C::*。
最后要防止用户取NULL的地址,NULL要表现的像指针一样,但其值不是指向真正的0,所以要对用户隐藏。
改进后例如以下:
class { public: template<class T> //模版 operator T*()const{return 0;}//返回一个T*的null指针。 template<class C,class T> operator T C::*() const{return 0;}//转换随意类型的null成员指针 private: void operator&() const ;//隐藏NULL的地址 }NULL; //仅仅有一个名字为NULL的对象