一、内联函数技术
内联函数是和普通函数原理不同的函数。普通函数调用时依据的是函数指针的寻址,将程序跳到函数定义中执行;而内联函数则是将函数调用都用函数定义覆盖。
内联函数有更高的执行效率,但会占用更多的空间。
要使用内联函数,请使用下面两种写法的至少一种:
1、在函数声明时先写上inline限定符
#include <iostream>
inline double square(double num);
int main(void)
{
double a;
std::cin>>a;
std::cout<<square(a);
}
double square(double num)
{
return num*num;
}
2、在函数定义时先写上inline限定符
#include <iostream>
inline double square(double num)
{
return num*num;
}
int main(void)
{
double a;
std::cin>>a;
std::cout<<square(a);
}
二、引用变量
引用变量是另一个变量的别名,如果引用变量b是引用变量a的别名,那么对b进行的操作和对a进行的操作是等价的!
1--定义方法
如果要定义int类型变量a的引用变量b,可以如下操作:
int a=10;
int &b=a;
这和指向a的指针c的定义方法有相似之处
int *c=&a;//指向a的指针c
不过,我们称变量b的类型为指向int型变量的引用!
2--引用变量必须初始化!
引用不能先声明再赋值,只能进行初始化,下面的写法是错误的:
int &b; //totally_wrong
b=a //totally_wrong
3--引用变量的忠诚性!
引用变量会和被指的那一个变量紧密联系在一起,不能在初始化引用变量后将改变其指向!
你可以将引用变量理解为一个指针常量,指向固定地址!
这就意味着,如下所示,变量b和(*pc)几乎是一模一样的!
int a;
int &b=a;
int* const pc=&a;
(这里有必要插一句,我所定义的pc是一个指针常量而不是一个指向常量的指针。两者的区分方法是,从定义的等号从右往左看,如果先读到const,说明这个变量的本质属性是一个常量,然后才是个指针,也就是这个变量是指针常量;从定义的等号从右往座左看,如果先读到*,说明这个变量本质属性是一个指针,然后通过const限定不能通过指针修改指向所指向的值!)
4--下面一段程序验证引用变量的性质
#include <iostream>
using namespace std;
int main(void)
{
int* num;
num=new int;
*num=1;
int &tnum=*num;
num=new int;
*num=2;
cout<<tnum;
}
//结果是1,而不是2
这说明两点重要信息:
首先,指针取地址符也可以对引用变量初始化,这相当于先分配变量空间再命名,很有意思!还有,初始化以后引用变量就认准了一块地址,不会再改变,即使用于初始化这个引用变量的指针已经变换指向!
那如果这个引用变量认准的空间被释放了会怎么样呢?
#include <iostream>
using namespace std;
int main(void)
{
int* num;
num=new int;
*num=1;
int &tnum=*num;
delete num;
cout<<tnum;
}
读者可以自行尝试发现,这样写的话,输出的结果就是未定义的了!
三、引用变量作为函数参数
1--
如果以普通变量作为函数参数,函数在运行时事实上没有访问这些普通变量,而是创建临时变量,将普通变量的值传递给临时变量,然后对临时变量进行访问。所以如下编写的交换函数是无效的!
#include <iostream>
using namespace std;
void swap(int a,int b)
{
int tmp=b;
b=a;
a=tmp;
}
int main(void)
{
int m=1,n=2;
swap(m,n);
cout<<"m="<<m<<endl;
cout<<"n="<<n;
}
可以采用指针的方法避免这一情况的出现,但C++还可以用引用!把引用变量作为参数,就可以解决这一问题
#include <iostream>
using namespace std;
void swap(int &a,int &b)
{
int tmp=b;
b=a;
a=tmp;
}
int main(void)
{
int m=1,n=2;
swap(m,n);
cout<<"m="<<m<<endl;
cout<<"n="<<n;
}
(结果是m=2,n=1)
注意,没有创建引用变量,但问题就这样解决了!它的解决方法是让a和b作为m和n的别名!(有趣的是,这并不意味着a和b这两个函数参数不可以与m和n重名,说明函数变量的独立性还是有的!)
2--
如下代码中出现了函数引用参数和实参类型并不匹配的情况,这时候编译器会创建临时变量来解决问题
#include <iostream>
using namespace std;
void swap(double &m,double &n)
{
double tmp=n;
n=m;
m=tmp;
}
int main(void)
{
int m=1,n=2;
swap(m,n);
cout<<"m="<<m<<endl;
cout<<"n="<<n;
}
按照C++ primer plus的说法,这时候编译器会创建临时变量,来替换m和n,这样swap函数的功能就不能实现了;然后,笔者尝试后,发现是可以实现的。。。。。。
只能说,这样的写法是不严谨的,最好别这么做,而且在现代的编译器中,这种做法无法通过编译!
3--const限定符
函数声明时加上const限定符号可以禁止通过引用来改变实参的值!
#include <iostream>
using namespace std;
void print(const int &m,const int &n)
{
cout<<m<<" "<<n;
}
int main(void)
{
int a=1,b=2;
print(a,b);
}
这时,如果在函数定义中加上m=3这样的赋值语句,是无法通过编译的!
四、引用变量作为返回值
1--
想不到吧,引用变量可以作为函数的返回值,返回指向某个类型某个变量的引用。以下是程序示例:
#include <iostream>
using namespace std;
int& myplus(int &a,int &b);
int main(void)
{
int m=1,n=10,p=100;
cout<<myplus(p,myplus(m,n));
}
int& myplus(int &a,int &b)
{
a=a+b;
return a;
}
myplus(m,n)函数返回了一个指向m的引用,它就可以被当作m使用!
2--注意,返回的引用的对于的内存空间必须存在,否则会出问题!
3--同样也可以在函数定义前加上const限定符,返回的引用就不可以作为左值被修改了!