《C++ Primer Plus》第8章知识点总结
C++内联函数
编译器将使用相应的函数代码替代函数调用。对于内联代码,程序无需跳到另一个位置处执行代码,再跳回来。因此,内联函数的运行速度比常规函数稍快,但代价是需要占用更多内存
要使用内联函数,必须采取下述措施之一:
(1)在函数声明前加上关键字inline
(2)在函数定义前加上关键字inline
通常的做法是省略原型,将整个定义(即函数头和所有函数代码)放在本应提供原型的地方
下面是一个例子
#include <iostream>
inline double square(double x){return x*x;}
int main()
{
using namespace std;
double a,b;
double c=13.0;
a=square(5.0);
b=square(4.5+7.5);
cout<<"a= "<<a<<", b= "<<b<<"\n";
cout <<"c= "<<c;
cout<<", c squared= "<<square(c++)<<"\n";
cout<<"Now c= "<<c<<"\n";
return 0;
}
运行结果:
a= 25, b= 144
c= 13, c squared= 169
Now c= 14
引用变量
创建引用变量
将rodents作为rats变量的别名
int rats;
int & rodents=rats;
注意:必须在声明引用变量时进行初始化
将引用用作函数参数
#include <iostream>
void swapr(int & a,int & b);
void swapp(int * p,int * q);
void swapv(int a,int b);
int main()
{
using namespace std;
int wallet1=300;
int wallet2=350;
cout<<"wallet1=$"<<wallet1;
cout<<"wallet2=$"<<wallet2<<endl;
cout<<"Using references to swap contents:\n";
swapr(wallet1,wallet2);
cout<<"wallet1=$"<<wallet1;
cout<<"wallet2=$"<<wallet2<<endl;
cout<<"Using pointers to swap contents again:\n";
swapp(&wallet1,&wallet2);
cout<<"wallet1=$"<<wallet1;
cout<<"wallet2=$"<<wallet2<<endl;
cout<<"Trying to use passing by value:\n";
swapv(wallet1,wallet2);
cout<<"wallet1=$"<<wallet1;
cout<<"wallet2=$"<<wallet2<<endl;
return 0;
}
void swapr(int & a,int & b)//使用引用
{
int temp;
temp=a;
a=b;
b=temp;
}
void swapp(int * p,int * q)//使用指针
{
int temp;
temp=*p;
*p=*q;
*q=temp;
}
void swapv(int a,int b)//使用值
{
int temp;
temp=a;
a=b;
b=temp;
}
结果如下
wallet1=$300wallet2=$350
Using references to swap contents:
wallet1=$350wallet2=$300
Using pointers to swap contents again:
wallet1=$300wallet2=$350
Trying to use passing by value:
wallet1=$300wallet2=$350
在swapr()中,变量a和b是wallet1和wallet2的别名,所以交换a和b的值相当于交换wallet1和wallet2的值
但在swqpv()中,变量a和b是赋值wallet1和wallet2的值的新变量,因此交换a和b的值并不影响wallet1和wallet2的值
将引用用于结构
只需在声明结构参数时使用引用运算符&即可
将引用用于类对象
对象、继承和引用
何时使用引用参数
(1)程序员能够修改调用函数中的数据对象
(2)通过传递引用而不是调用函数中断数据对象
引用、指针、按值传递指导原则
1、对于使用传递的值而不作修改的函数
(1)如果数据对象很小,如内置数据类型或小型结构,则按值传递
(2)如果数据对象是数组,则使用指针,因为这是唯一的选择,并将指针声明为指向const的指针
(3)如果数据对象是较大的结构,则是有那个const指针或const引用,以提高程序的效率。这样可以节省复制结构所需的时间和空间
(4)如果数据对象是类对象,则使用const引用。类设计的语义常常要求使用引用,
2、对于修改调用函数中数据的函数
(1)如果数据对象是内置数据类型,则使用指针
(2)如果数据对象是数组,则只能使用指针
(3)如果数据对象是结构,则使用引用或指针
(4)如果数据对象是类对象,则使用引用
默认参数
char* left(const char* str,int n=1)
这是一个函数的函数原型,该函数返回了一个新的字符串,设置了n的默认值为1。对于带参数列表的函数,必须从右向左添加默认值。也就是说,要为某个参数设置默认值,必须为它右边的所有参数提供默认值。
实参按从左到右的顺序依次被赋给相应的形参,而不能跳过任何参数,所以下面调用是不允许的
beeps=harpo(3, ,8);
函数重载
一些看起来不同的特征标是不能用来重载的,例如下面情况是不允许的
(1)double cube(double x);
double cube(double & x);
(2)void dribble(char* bits);
void dribble(const char* bits);
函数模版
简单来说,就类似java的泛型。函数模版允许以任意类型的方式来定义函数,例如,可以这样建立一个交换模版
template <typename AnyType>
void Swap(AnyType &a,AnyType &b)
{
AnyType temp;
temp=a;
a=b;
b=temp;
}
第一行指出,要建立一个模版,并将类型命名为AnyType。关键字template和typename是必需的,除非可以使用关键字class代替typename
模版的重载和函数重载类似,而且重载是不一定都要是泛型,可以有泛型也可以有不是泛型的
具体化的3种
(1)隐式实例化(implicit instantiation)
普通的调用模版就是隐式实例化
(2)显示实例化(explicit instantiation)
直接命令调用编译器创建特定的实例。即调用模版时,声明所需的种类——用<>符号指示类型,并在声明前加上关键字template
template void Swap<ing>(int,int);
意思就是“使用Swap()模版生成int类型的函数定义”
(3)显示具体化(explicit specialization)
与显式实例化不同,下面两个声明等价
template <> void Swap<int>(int &,int &);
template <> void Swap(int &,int &);
这两个声明的意思是“不要使用Swap()模版来生成函数定义,而应使用专门为int类型显示地定义的函数定义”,这些原型必须有自己的函数定义
显示具体化
下面是用于交换job结构的非模版函数,模版函数,具体化的原型
void Swap(job &a,job &b);
template<typename T>
void Swap(T &a,T &b);
template <> void Swap<job>(job &a,job &b);
编译器在选择原型时,非模版版本>显示具体化>模版版本实例化和具体化