第8章 函数探索
8.1C++内联函数
(1)常规函数的执行过程:
执行到函数调用指令时,程序将在函数调用后立即存储该指令的内存地址,并将函数的参数复制
到堆栈(为此保留的内存块),跳到标记函数起点的内存单元,执行函数代码(也许还将返回值
放入到寄存器中),然后跳回到地址被保存的指令处。
(2)内联函数:
[1]代码执行时间短,函数经常被调用
[2]定义:编译器将使用相应的函数代码替换函数调用,程序无需再跳到另一个位置处执行,在跳 回来
[3]如何选择:
如果执行函数代码的时间比处理函数调用机制的时间长,则节省时间将只占整个过程的很小一部
---- ------
分
[4]内联函数不能递归
[5]请求将函数作为内联函数时,编译器并不一定会满足这种要求
[6]内联与宏
#include<iostream>
#define SQUARE(x) ((x)*(x))
inline double square(double x) {return x*x;}
using namespace std;
int main()
{
int c=2;
//cout<<c++*c++<<endl;
cout<<SQUARE(c++)<<endl; //c++*c++
cout<<c<<endl; //c递增两次,宏不能按值传递
int d=2;
cout<<square(d++)<<endl;//d递增一次
cout<<d<<endl;
return 0;
}
8.2引用变量
8.2.1
(1)典型用途:作为函数参数,结构和对象的参数
(2)必须声明引用变量是初始化
(3)引用更接近const指针,必须在创建时初始化
int &rodents = rats;
int * const pr = &rats;
#include<iostream>
using namespace std;
int main()
{
int rats = 101;
int &rodents = rats;
cout<<"rat = "<<rats;
cout<<",rodents = "<<rodents<<endl;
cout<<"rats address = "<<&rats;
cout<<",rodents address = "<<&rodents<<endl;
int bunnies=50;
rodents = bunnies; //可以通过初始化声明来设置引用,但不能通过赋值来设置
cout<<"bunnies = "<<bunnies;
cout<<",rats = "<<rats;
cout<<",rodents = "<<rodents<<endl;
cout<<"bunnies address = "<<&bunnies;
cout<<",rats address = "<<&rats;
cout<<",rodents address = "<<&rodents<<endl;
return 0;
}
int rats = 101;
int * pt = &rats;
int &rodents = &pt;
int bunnies = 50;
pt = &bunnies;
rodents 引用的还是rats
8.2.2
(1)按值传递和按引用传递
(2)函数调用使用实参初始化形参,因此函数的引用参数被初始化为函数调用传递的
8.2.3
实参的类型与引用参数类型不匹配,但可被转换为引用类型,程序将创建一个正确类型的临时变量
(1)什么时候创建临时变量?(如果引用参数是const)
[1]实参的类型正确,但不是左值
[2]实参的类型不正确,但可以转换为正确的类型
什么是左值?P271
可以被引用的数据对象,如:变量,数组元素,结构成员,引用,???解除引用的指针???
非左值,如:字面变量(5.0)(用引号括起的字符串除外)
(2)将引用参数声明为常量数据的引用的理由:
[1]使用const可以避免无意中修改数据的编程错误;
[2]使用const使函数能够处理const和非const实参,否则将只能接收非const数据;
[3]使用const引用使函数能够正确生成并使用临时变量。
8.2.4
(1)返回值为引用:
返回引用的函数实际上是被引用变量的别名
(2)注意问题:
避免返回函数终止时不再存在的内存单元引用(返回一个指向临时变量的引用)
解决方法:
[1]返回一个作为参数传递给函数的引用
[2]???用new来分配新的存储空间
const free_throws & clone(free_throws &ft)
{
free_throws *pt;
*pt = ft;
return *pt;
}
free_throws &jolly = clone(three);
(3)const用于引用返回类型
返回const引用是不可修改的左值,
8.2.7何时使用引用参数
8.3
默认参数:当函数调用中省略了实参时自动调用的一个值
#include<iostream>
#include<cstring>
using namespace std;
char *left(char *str,int n=1)
{
if(n<0)//用户要求字符数目为负
{
n=0;
}
//用户要求字符数目可能多于字符串包含的字符数
int len=strlen(str);
n=n<len?n:len;
char *p=new char [n+1];
int i;
for(i=0;i<n;i++)
{
p[i]=str[i];
}
p[i]='\0';
return p;
}
int main()
{
char str[1024];
int n;
while(cin>>str/*>>n*/)
{
cout<<left(str/*,n*/132323)<<endl;
}
return 0;
}
8.4
(1)函数重载:名称相同,参数数目和/或参数类型不同和/或返回类型不同
类型引用和类型本身视为同一个特征标
(2)一个数字左边几位
unsigned long left(unsigned long num,unsigned ct)
{
unsigned digits = 1;
unsigned logn n = num;
if(ct == 0||num == 0)
{
return 0;
}
while(n/=10)
{
digits++;
}
if(digits>ct)
{
ct = digits - ct;
while(ct--)
{
num/=10;
}
return num;
}
else
{
return num;
}
}
(3)何时使用?
P289
函数基本上执行相同的任务,但使用不同形式的数据时
使用一个但默认参数的函数简单些
8.5函数模板
(1) template<typename T>
void Swap(T &a,T&b)
{
T temp;
temp = a;
a = b;
b = temp;
}
template<typename T>
void Swap(T a[],T b[],int n)
{
T temp;
for(int i=0;i<n;i++)
{
temp = a[i];
a[i] = b[i];
b[i] = temp;
}
}
(2)显示具体化 template <typename T>
void Swap(T &,T &) --模板函数
void Swap(job &,job &) --非模板函数
当编译器找与函数调用匹配的具体化定义时,将使用该定义,而不再寻找模板
struct job
{
char name[40];
double salary;
int floor;
};
template<>void Swap<job>(job &j1,job &j2) --具体化原型
{
double t1;
int t2;
t1= j1.salary;
j1.salary=j2.salary;
j2.salary=t1;
t2=j1.floor;
f1.floor=j2.floor;
j2.flooe=t2;
}
template<typename T>
void Swap(T &a,T &b)
{
T temp;
temp=a;
a=b;
b=temp;
}
8.5.4
(1)编译器使用模板为特定类型生成函数定义时,得到函数模板的实例
(2)模板并非函数的定义,但是使用int的模板实例是函数定义
(3)隐式实例化:由于调用Swap()函数时提供了int
(4)显示实例化:直接命令编译器创建特定的实例
template void Swap<int>(int,int);
(5)显示具体化template<>void Swap<int>(int&,int&);
template<>void Swap(int &,int &)
(6)试图在同一个文件(或转换单元)中使用同一种类型的显示实例化和显示具体化将出错
(7)显示实例化:template
显示具体化:template<>
8.5.5
(1)指向非const数据的指针和引用优先于非const指针和引用参数列表
const和非const之间的区别只适用于指针和引用指向的数据
二义性错误:
struct blot {int a; char b[10]};
blot ink={25,"sports"};
recycle(ink);
void recysle(blot);
void recycle(const blot);
(2)一个完全匹配优先于另一个的另一种情况,非模板函数优先于模板函数(显示具体化)
(3)如果两个完全匹配的函数都是模板函数,则较具体的模板函数优先
struct blot {int a; char b[10]};
blot ink={25,"sports"};
recycle(&ink); 选#2
template<class Type> void recycle(Type t) #1
template<class Type> void recycle(Type *t) #2
两个隐式实例
recycle<blot*>(blot*) #1
recycle<blot>(bloe *) #2