引用与const的结合用法
引用的基本概念:
(1)引用其实就是给变量其一个别名
(2)其语法形式:变量类型 &别名=原名 例:int &b=a
(3)引用必须进行初始化,int&b是不对的
(4)引用一旦初始化之后就不可更改了
(5)引用的传递:传递有值传递和地址传递。引用传递就是地址传递,通过引用参数产生的效果同按照地址传递是一样的
(6)不要反悔局部变量的引用。函数的调用可以作为左值(如果函数的返回值是引用,这个函数调用可以作为左值)
(7)引用的本质:在C++内部实现是一个指针常量
例:int &a=b;自动转换为int const a=&b,指针常量到的指向不可更改,这也说明了为什么引用不可更改。b=20;内部发现a是引用,自动回帮我们转化为a=20;
int main()
{
int a = 10, b = 20;
//int &d1 = a;
//a = 20;
//&d11 = b;//因为引用不可改变,b1已经引用a,不可再引用b
const int& d1 = a;
a = 100;
printf("%d %d", a, d11);
const int d3 = 1;
const int& d4 = d3;//const常量也必须用常引用
const int& d5 = 8;//常量具有常属性,只有常引用可以引用常量
return 0;
}
引用与指针的结合用法
先看一段小代码:
int *&pref=p;//
int &*pref=p;//
解释:
一般这种解释是从右向左解释的
(1)p是一个指针,给它定义了一个别名pref,什么类型的引用呢?是int *类型(整形类型指针)的引用。正确
(2)p是一个指针,定义了一个指针prev指向引用,引用本身是没有空间的。错误
int a=10,b=20;
int *p1=&a;
const int *p2=&a;
int *const p3=&a;
const int *const p4=&a;
通过上边分析下边对错:
注意一个细节:别名的改变会引起指针的改变
int *&pref=p1;//对
int *&pref=p2;//错
//因为*p2是被限制的,而*pref的改变,会引起*p2的改变 改正:const int *&pref=p2;
int *&pref=p3;//错
//因为p2是被限制的,而pref的改变会引起p2的改变 改正:int *const &pref=p3;
int *&pref=p4;//错
//这里*p2和p2都被限制了,所以必须同时限制*pref和pref 改正:const int*const & pref = p4;
const与函数返回值的结合使用
注意:在函数后边加const其实约束的还是this指针,下边两种写法是等价的
//const Int*GetValue(cosnt Int *const this )
const Int* GetValue()const
{
return &value;
}
#include<iostream>
using namespace std;
class Int
{
private:
int val;
public:
Int(int x = 0) :val(x) { cout << "Create Int: " << this << endl; }
~Int() { cout << "Destroy Int: " << this << endl; }
Int(const Int& x) :val(x.val)//拷贝构造
{
cout << "Copy Create Int: " << this << endl;
}
Int(Int&& x)//移动拷贝
{
val = x.val;
cout << "Move Copy Create Int: " << this << endl;
}
Int& operator=(const Int& x)//赋值函数
{
if (this != &x)
{
val = x.val;
}
cout << this << " <= " << &x << endl;
return *this;
}
Int& operator=(Int&& x)//移动赋值函数
{
if (this != &x)
{
val = x.val;
}
cout << this << " Move = " << &x << endl;
return *this;
}
//c11
Int* operator&() { return this; }
const Int* operator&() const { return this; }
int& Value() { return val; }
const int& Value() const { return val; }
};
//下面对四种返回值与const的结合运用进行分析
class Test
{
private:
Int value;
public:
Test(int x = 0) :value(x) {}
~Test() {}
Int GetValue()//以值的形式返回,构建临时对象
{
return value;
}
Int &GetValue()
{
return value;
}
const Int &GetValue() const//const约束的是this指针,指针的常性传递是向能力缩小的方向传递的 。
{
return value;
}
Int*GetValue()const
{
return &value;
}
const Int* GetValue()const
{
return &value;
}
};
//主函数一:
int main()
{
Test ta(10);
Int a1 = ta.GetValue();//对
Int& a2 = ta.GetValue();//错
//临时量不可引用
const Int& a3 = ta.GetValue();//对
//这里会直接绕过对临时对象的构建,直接构建新对象a3
Int* p1 = &ta.GetValue();//对
//构建一个临时对象,用p1去指向这个对象的地址,但这个对象的生存期仅仅限于这条语句
const Int* p2 = &ta.GetValue();//对
return 0;
}
执行结果:
//主函数二:
{
Test ta(10);
Int a1 = ta.GetValue();
Int& a2 = ta.GetValue();
const Int& a3 = ta.GetValue();
Int&& a4 = ta.GetValue();//错
const Int&& a5 = ta.GetValue();//错
//右值引用引用的必须是纯右值或者将亡值(将亡值指的是以值的形式返回的中间过度者)
Int* p1 = &ta.GetValue();
const Int* p2 = &ta.GetValue();
Int* const p3 = &ta.GetValue();
const Int* const p4 = &ta.GetValue();
return 0;
}
注意:引用的本质就是指针,返回引用其实就是返回地址,当编译器发现返回值是以值的形式接受时,就会以这个地址所指的值作为参数调动构造函数去构造一个新对象;对于引用来说,它只是这个返回值的一个别名,并没有构造新对象,指针也一样,指针只是指向这个地址。并不会通过它去构造新对象。
执行结果:
//既然是以常引用返回,那就必须以常引用来接收
//主函数三:
{
Test ta(10);
Int a1 = ta.GetValue();
Int& a2 = ta.GetValue();//错
const Int& a3 = ta.GetValue();
Int* p1 = &ta.GetValue();//错
const Int* p2 = &ta.GetValue();
Int* const p3 = &ta.GetValue();//错
const Int* const p4 = &ta.GetValue();
return 0;
}
执行结果:
主函数四:
int main()
{
Test ta(10);
Int a1 = *ta.GetValue();
cout << endl;
Int& a2 = *ta.GetValue();
const Int& a3 = *ta.GetValue();
//Int*&& a4 = ta.GetValue();
//const Int&& a5 = ta.GetValue();
Int* p1 = ta.GetValue();
const Int* p2 = ta.GetValue();
Int* const p3 = ta.GetValue();
const Int* const p4 = ta.GetValue();
}
主函数五:
加const之后全对
int main()
{
Test ta(10);
cout << endl;
Int a1 = *ta.GetValue();
cout << endl;
Int& a2 = *ta.GetValue();//错
cout << endl;
const Int& a3 = *ta.GetValue();
cout << endl;
Int*&& b1 = ta.GetValue();//错int*类型的字面常量
Int* p1 = ta.GetValue();//错
const Int* p2 = ta.GetValue();
Int* const p3 = ta.GetValue();//错
const Int* const p4 = ta.GetValue();
}
附加模板:
template<class Type,size_t N>
void Printf(Type(&br)[N])
{
for(Type &x:br)
{
printf("%d \n",x);
}
}
引用:int ar[10]
int (&br)[10]=ar;