引用
我们定义一个整型变量 a ,并赋值10;
int a = 10;
整型数据占4个字节,a是一个标识符,这个标识符代表这个空间,对这个标识符的操作,就是对这块空间的操作。
那么引用呢,就是给这段空间起一个小名,原本它被称为 a ,现在我们也可以叫它其他的名字。
引用的格式:类型 & 小名 = 原名;
例如:
int &b = a; //b就是对a的引用
别名依赖于原名,普通引用必须初始化。
int &c; //这就是一个错误,没有指定c是谁的引用
用途:代替指针,有更好的可读性和实用性。
例如在交换两个数的值时:
地址传递时:
void swap(int *a, int *b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
int main()
{
int a = 10;
int b = 20;
swap(&a, &b);
cout<<"a = "<<a<<", b = "<<b<<endl;
return 0;
}
引用时:
void swap(int &pa, int &pb)
{
int tmp = pa;
pa = pb;
pb = tmp;
}
int main()
{
int a = 10;
int b = 20;
swap(a, b);
cout<<"a = "<<a<<", b = "<<b<<endl;
return 0;
}
在以往使用结构体时,经常会将整个结构体作为参数进行传递,这样做会浪费很多资源,而引用也可以解决这个问题。
struct Student
{
int age;
char name[20];
};
void printS(Student &s)
{
printf ("age = %d, name = %s\n",s.age, s.name);
}
int main()
{
Student stu = {10, "小明"};
printS(stu);
return 0;
}
说明:
引用是有空间的,为4个字节,引用使用之前必须初始化。(除了在结构体中,不需要初始化,求取引用的长度也是利用结构体)
引用的本质是一个常指针。
char &b = a; ⇒ char *const b = &a;
引用作为函数的返回值:
int& test1()
{
int a = 10;
return a;
} //错误,不能返回一个局部变量的引用,因为函数执行完后,栈空间会被释放
int& test2()
{
static int a = 20; //static 只会被初始化一次
a++;
return a;
}
int main()
{
int &b = test2();
cout<<"b = "<<b<<endl; // b = 21;
b = 100;
test2();
cout<<"b = "<<b<<endl; // b = 101;
test2() = 200;
cout<<"b = "<<b<<endl; // b = 200;
return 0;
}
说明:
1.不能返回一个局部变量的引用,问题在于函数运行结束后,栈空间会被释放
2.如果一个函数返回的是引用,则改函数可以作为左值使用
在学习链表时,我们经常会遇到二级指针,在初始化时,我们会用到,往往这也会称为出错最多的地方,而指针引用也可以解决这个问题。
void init1(Teacher **p)
{
*p = (Teacher *)malloc(sizeof(Teacher)/sizeof(char));
if (*p == NULL)
{
return;
}
(*p)->age = 10;
strcpy((*p)->name, "小明");
}
void init2(Teacher* &p)
{
p = (Teacher *)malloc(sizeof(Teacher)/sizeof(char));
if (p == NULL)
{
return;
}
p->age = 10;
p->name = (char *)malloc(sizeof(char)*100);
strcpy(p->name, "小明");
}
int main()
{
Teacher *pt = NULL;
// init1(&pt);
init2(pt);
printf ("age = %d, name = %s\n", pt->age, pt->name);
return 0;
}
init1是我们最常用的一种方式,但很容易用错,不防用引用来优化这种方法。
常引用:不能通过引用来改变变量的值;
1.用普通变量取初始化常引用,不能通过引用来改变变量的值;
const int &b = a; ===> const int* const b = &a;
1.b的值不允许改变,即 b = &c;是不允许的
2.b指向的值不能变,简单的理解: *b是不能变的 ==> *b不能做左值 *b = 20;也是不允许的
但变量 a 自身可以发生变化,即 a = 20;是可以的
2.用一个常量去初始化常引用
const int &a = 10; ==> const int* const a = &10;
如果是一个常量,编译器会分配一个空间去存放这个常量值,引用代表这个空间
内联函数
宏函数的优点:宏函数没有正常函数的出栈和入栈的开销,能提高运行效率;
缺点:每一次展开,会使得整个程序显得冗长。
例如:
#define MAX(a,b) ((a) > (b)) ? (a) : (b))
#define LENGTH(a) (sizeof(a) / sizeof(a[0]))
C++建议用内联函数代替宏函数
特点:
1.内联函数在编译时处理,而宏函数在预处理的时候处理;
2.内联函数是一种请求,不一定成功;
3.内联函数一旦成功,函数体在运行的时候是不存在的,因为其存放在符号表中,不能进行取地址操作,也不能作为回调函数;
请求成功的因素:函数体不能太大,一般不超过5行;不能有任何形式的循环语句;不能有很复杂的判断语句。
内联函数的定义:
inline int add(int a, int b)
{
return a+b;
}
注意:inline 关键字一定要在函数定义的时候写,而不是函数声明,否则编译器会忽略该请求。
现代C++编译器能够进行编译优化,因此一些函数即使没有inline声明,也可能被编译器内联编译。
默认参数
在函数定义的时候可以给函数的形参设置一个默认的值,如果调用时没有传入相应的参数,则使用默认参数。
规则:
1.当函数的某一个形参有默认值时,它右边所有的形参都必须有默认参数。
2.默认参数如果写在声明中,则在定义时,不要再写默认参数;相反,如果在定义时,写了默认参数,那么声明时就不要写,二者择其一。
int add(int a, int b = 5)
{
return a+b;
}
int main()
{
int a = add(5);
int b = add(5, 10);
cout<<"a = "<<a<<", b = "<<b<<endl; // a = 10, b = 15
return 0;
}
占位参数
占位参数只有类型声明,没有变量名
int func(int a, int) //调用时,必须传两个参数
{
return a;
}
int main()
{
int c = func(5, 10);
cout<<"c = "<<c<<endl; //c = 5;
return 0;
}
通常,默认参数与占位参数一起使用
int func(int a, int = 5)
{
return a;
}
int main()
{
int c = func(5);
cout<<"c = "<<c<<endl; //c = 5;
return 0;
}
这里再补充一个位字段,位域
struct B
{
unsigned int a : 4; //a的范围为0-15
unsigned int b : 5; //b的范围为0-31
unsigned int : 5; //无名字段
};
int main()
{
B bb;
bb.a = 15;
bb.a++;
bb.b = 32;
cout << "bb.a = " <<bb.a <<endl; // bb.a = 0
cout << "bb.b = " <<bb.b <<endl; // bb.b = 0
return 0;
}
函数重载
用同一个函数名,通过匹配不同的参数调用不同的函数;
函数重载的条件:
1.函数参数不同;
2.参数类型不同;
3.参数类型不同;
注意:函数的返回值不能作为重载的判断条件
#include <iostream>
void print(int a)
{
std::cout << "a = "<< a << std::endl;
}
void print(int a, int b)
{
std::cout << "a = " << a << ", b = " << b << std::endl;
}
void print(char *ptr)
{
std::cout << "ptr = " << ptr << std::endl;
}
typedef void(*FUNC)(int);
typedef void(*FUNC2)(int, int);
int main()
{
int a = 10;
int b = 15;
char *ptr = "hello";
FUNC p = print;
FUNC2 p2 = print;
printf("p = %p\n", &p);
printf("p2 = %p\n", &p2);
print(a);
print(a, b);
print(ptr);
return 0;
}