int a = 1; int& b = a; int& c = a; int& d = a; cout<<&a<<" "<<&b<<" "<<&c<<" "<<&d<<endl; cout<<a<<" "<<b<<" "<<c<<" "<<d<<endl;
int a = 1; int& b = a; const int& c = a; const int& d = 10;
const int a = 10; int& b = a; //错误的,是权限的放大。
int d = 10; double e = d; //隐式类型的转换。
int a = 1; int& b = a; double& c = a; //这里会报错----->隐式类型转换,中间有临时变量,临时变量具有常性。 const double& d = a; //这个确实正确的
但是这样就是正确的:
int a = 1; const int& b = a;
引用的应用
int Big(int a,int b) { if(a > b) { return a; } return b; } int main() { const int& r = Big(3,5); cout<<r<<endl; system("pause"); return 0; }
但是如果我们在主函数中接收返回值时去掉const,程序就会报错。原因和上面的原因相同,在返回时会生成一个临时变量(在寄存器中),而临时变量具有常性。
int& Big(int a,int b) { if(a > b) { return a; } return b; } int main() { int& r = Big(3,5); system("pause"); return 0; }
int& r = Big(3,5); //结果是5 Big(10,5); //结果是10;
用引用做参数:
void Swap(int& a,int& b) { int tmp = a; a = b; b = tmp; } int main() { int a = 10; int b = 20; Swap(a,b); return 0; }
2.如果是很大的,在传值时就是拷贝,就会浪费空间和造成效率低。所以可以传引用,但是传引用时,在函数体内改变了,就会导致在函数体外也会被改变,因此可以在引用的参数前加const.
sizeof(引用)------>是变量的大小。
sizeof(指针)------->是4(32位系统)。
指针(++/--)------->加/减类型的大小。
引用(++/--)-------->加/减1.
class Student { public: void Show() { cout<<_name<<" is "<<age<<endl; } public: char* _name; int age; }; int main() { Student A; A._name = "huhu"; A.age = 6; A.Show (); system("pause"); return 0; }
内联函数(inline)
以inline修饰的函数叫做内联函数,C++编译时会在调用内联函数的地方进行展开,没有函数压栈的开销,提高了程序的运行效率。
内联函数的调用过程:在调用一个内联函数时,编译器首先会检查调用是否正确(如:进行类型安全检查)。如果正确,内联函数的代码会直接替换函数调用,所以就省去了函数调用栈帧的开销。这里与预处理有显著的区别,因为预处理器不能进行类型安全的检查。
特点:
- inline函数是一种以空间换时间的做法,省去函数在调用过程中栈帧的开销。
- inline必须与定义放在一起,才能成为内联函数。仅与声明放在一起是不起任何作用的。
- 定义在类内成员函数默认为内联函数。
- inline对于编译器而言只是一种建议,编译器会自动优化。当inline函数内部有循环/递归等,编译器优化时会忽略掉内联。
缺点:内联函数是以代码膨胀为代价的,仅仅省去了函数栈帧的开销。如果执行函数体内代码的时间,相较于函数调用的开销大,那么效率反而会降低。另一方面,每一处内联函数调用都会复制代码,将程序的代码量增大,消耗更多的内存空间。
下面我们写一个实例:
class AA { public: void Show() //定义在类内的成员函数默认为内联函数 { cout<<"Show()"<<endl; } void Display(); private: int _a; int _b; }; inline void AA::Display() //inline关键字要与定义放在一起 { cout<<_a<<endl; cout<<_b<<endl; }
友元函数
关键字:friend;
特点:在C++中,友元函数允许在类外访问类内的任何成员,就像成员函数一样。
强调:
- 友元函数不是类的成员函数;
- 友元函数可以通过类的对象访问任何成员,包括私有和保护。
class Date { public: Date(int year,int month,int day) :_year(year) ,_month(month) ,_day(day) {} friend void Display(const Date& d); friend ostream& operator<<(ostream& out,const Date& d); //重载<<符号 friend istream& operator>>(istream& in,Date& d); // 重载<<符号 private: int _year; int _month; int _day; }; void Display(const Date& d) { cout<<d._year<<"-"<<d._month<<"-"<<d._day<<endl; } ostream& operator<<(ostream& out,const Date& d) { out<<"年:"<<d._year <<endl; out<<"月:"<<d._month <<endl; out<<"日:"<<d._day <<endl; return out; } istream& operator>>(istream& in,Date& d) { in>>d._year ; in>>d._month ; in>>d._day ; return in; }
注意:在重载<<和>>符号时,就必须用到友元函数了,因为在成员函数中会有this指针,而this指针总是第一个参数,而<<和>>符号需要两个参数,而当是<<符号时,为了提高代码的可读性,就要把类的对象放在右边,但是this指针却是第一个参数(会出现在左边)。这样就不符合我们的要求了。所以在这儿可以用友元函数来实现输入输出运算符的重载。
注意:友元函数会破坏代码的封装性,所以,在很多场合下并不推荐使用友元函数。
static修饰的类的静态成员
特点:在类里面,用static修饰的成员,成为类的静态成员。
类的静态成员,被类的所有对象共享。
class Date { public: Date(int year,int month,int day) :_year(year) ,_month(month) ,_day(day) { ++_count; } static void GetCount() { //在static函数内部,不可以调用非static成员,因为没有this指针,无法进行访问 cout<<Date::_count <<endl; //因为用static修饰的类的成员函数,没有this指针,所以只能通过类来访问 } private: int _year; int _month; int _day; static int _count; }; int Date::_count = 0;
敲黑板划重点啦:在类的静态成员函数中不可以访问非静态成员函数。在静态成员函数中没有this指针。
而在类的非静态成员函数中可以访问类的静态成员函数。