ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
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指针。 }; const NullClass NULL;//NULL的常量 ~~~ 然后再次使用 f(NULL)的时候,就会调用隐式的类型转换,获得一个对象T类型的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的对象 ~~~