C++在函数中扩展不少地方。主要在源码上。主要有如下几项
1.参数缺省值
2.内联函数
3.重载函数.
4.重载的实现原理和影响。
但是为为了实现重载又在编译结果做了一些特殊处理。这样带了一些连锁反应,这样在一些底层程序编写时要对函数做一些特殊处理。
一.参数缺省值
函数的参数缺省值就是指在调用函数时,有一些部分形参的值如果没有赋值,将会被赋给一个缺省值,象如下代码
void print(int a,int b=20,int c=30) { printf("a=%d,b=%d,c=%d\n",a,b,c); }
void test1() { print(1,2,3); //完整调用
print(1,2) ; //c将等于30;
print(1); //b将等于20,c将等于30
}
|
上述代码中print()中的b,c就是使用缺省值。
缺省值的作用,缺省值的主要作用用于扩展函数功能。在C中老的函数如果改变了参数定义,必须把所有引用这个函数的地方重改写编译一次。而且有了缺省值后。原有调用不变,而新增参数使用缺省值。这样就无需调整原有代码而可以使用新的功能了。
另外一个功能是把最高频使用的参数值做成缺省值,这样可以调用语句最简单。
参数缺省值有其优点,但是使用起来有很多限制.
限制1. 带缺省值参数要定义在不带缺省值参数后面
int func1(int a=30 ; int b) ; 是错误定义
限制2.调用函数时, 如果定义在前面参数采用缺省值,但后面参数不使用缺省值, 将产生编译错误
int func(int a = 10, int b=20);
func(,30); //这是错误用法。
限制3.参数缺省值的声明只能出现一次。 不能同时出现在外部声明和函数实现中,下例将产生编译错误
extern int func(int a= 10 ; int b=20);
int func(int a=10; int b=20)
{
}
二.内联函数
内联函数是指在函数声明或实现时加上inline关键字。这种函数有一般函数绝大部分特性。比如有类型检查,可以单步调试,函数内部的书写也跑普通函数一样。比如下例
inline float converter(float dollars);
内联函数跟一般函数的最大区别是在编译时,内联函数将源码直接在调用的地方展开,因此也不存在函数调用时,参数和局域变量压栈和出栈的开销。频繁调用的小函数最适合定义成内联函数.
代码展开这一点象多语句宏。但是多语句宏的缺点也很多。一是没有类型检查.二是碰到++,--很容易出错,三是无法单步调试。 inline 就比较完美解决这三个问题.因此C++也大量使用内联函数。
inline void swap03(int &a ,int &b) { int tmp = a; a = b; b = tmp; }
|
但是注意几点。
C++ 编译器有可能会忽略inline关键字,而且 不允许为不同的源文件中的内联函数指定不同的实现。
三.函数重载
C语言有重要一条,在同一个程序中,函数不能重名,因为最后会被链接不同地址上去。因此C语为了解决重名的问题,一般是采用在函数名前面或后面加入前缀或后缀来解决名字冲突。
如 list_init();
但是C++对于这一点没有这么严格,只要不同的参数列表,函数可以重名,这种叫函数重载(overload).这里不同的参数列表的条件非常简单,只如下三个条件只要满足一条即可以重载。
参数的个数,对应位置参数的类型,参数的排列顺序。
象如下就典型的重载函数
int max(int a,int b) { return (a>b? a : b); }
double max(double a,double b) { return (a>b? a : b); }
char max(char a,char b) { return (a>b? a : b); }
const char max(const char a,const char b) { return (a>b? a : b); }
|
注意两点,一个类型加上 const 后算另一个类型,比如C++中,const int 和int 算两个类型。如果参数完全相同,只有返回值不同,不能重载。
编译器通过调用时参数的个数和类型确定调用重载函数的哪个定义
4.重载的实现原理和影响。
C++是如何实现重载的?我们可以在Linux下用nm来导出符号表来看一下,其中C的函数名在符号表里没有变,但是C++的函数名会被编译器增加一些前缀和后缀
如重载的max在符号表里实际上是这样的.换句话说,在链接时还是用不同的名字,
080484a8 T _Z3maxdd
08048464 T _Z3maxii
C++编译器就是这个方法来实现重载,不同平台C++编译器加后缀的方法虽然不同,但实现思咱是一样的。
这个加后缀的方法带来什么影响?一个影响是当C++函数去调用C编译出来程序。会产生"错觉",也会加后缀来链接C函数。这样会产生链接错误。为了解决这个问题。在C++中可以用extern "C" 来声明是C函数,这样C++ 链接时,不会把C函数名加后缀
extern int c_func(int a,int b); //单个定义
extern "C" { //成片定义 int c_func1(int a,int b); int c_func2(int a,int b); }
|
这也是是为什么C的库函数的头文件为什么要加上这样一段。
#ifndef __STD_IO_H__ #define __STD_IO_H__
#ifdef __cplusplus extern "C" { #endif
// C函数定义
#ifdef __cplusplus } #endif
#endif /* __STD_IO_H__ */
|
___cplusplus是编译器内置宏。当编译器是C++才定义,在C编译器下相当什么都没加,而在C++链接时,而把所有extern "C" 包含的函数都定义成C函数。
练习题
1.C++怎么引用汇编语言的"函数"?
汇编采用label来实现类似函数功能,本质上跟 C函数一样,同样在C++中要用extern "C"声明;
2.还有一种奇怪的应用,在C编译器下,怎么链接C++的库或目标文件?换句话说就是C怎么样调用C++程序!
同样还是用extern "C" ,在C++程序,定义一个extern "C"的代理函数。在C程序中通过代理函数来间接调用C++函数
阅读(1457) | 评论(0) | 转发(0) |