const

本来以为const很温顺,单单表示不能改变的状态就可以了,后来发现不是一般的麻烦。

const跟引用,指针,auto,decltype都有联系。

1、纯纯的const

#include <iostream>
using namespace std;
int main(){
	int a=1;
	const int b=2;
	int const c=3;
	const int d=a;
	int e=b;
	cout<<a<<" "<<b<<" "<<c<<" "<<d<<" "<<e;
	return 0;
} 

int类型和const int 类型可以互相赋给对方,毫无压力/

2、与引用勾搭的const

int main(){
	string FirstPassword;   
	cin>>FirstPassword;		
	const string &SecondPassword=FirstPassword; 
 	cin>>FirstPassword;
	 cout<<SecondPassword; 
	return 0;
} 

强调的只是绑定状态的不改变;上面的第一密码不仅不是常数甚至还可以一直输入一直改变值。

不同于纯纯的状态,此时int const与 int 的互动发生了变化

int main(){
	int a;
	int const c=10;
	cin>>a;
	int const &b=a;           
	int &d=c;            //error 
	cout<<b<<"  "<<d; 
        return 0;
}

不能把const int 类型的变量赋给 int 型的引用;而const int 型的引用则是通杀。

也就是const与引用的结合中不存在 常量被绑定在板凳上,而板凳可以替换它的常量 的状况。

然而很魔性的东西是

int main(){
	const int &i=42;	
	return 0;
} 

如果没有const就感觉是无理取闹,像是把字面值赋给地址;然而此时的意义就变成了给变量i绑定了

一个值为42的字面值,而且不可以改变。

更魔性的是

#include <string>
using std::string;
using std::cin; 
using std::cout;
int main(){
	string FirstPassword,a;   //空字符串,而不同于NULL 
	cin>>FirstPassword;		//输入的字符串不能用空格,输出的想要空格用字符串字面值 
//	cout<<FirstPassword+" a"; 
	const string &SecondPassword=FirstPassword+" m";//去掉const报错了! 
	//cout<<SecondPassword;		//此常量引用与之绑定的对象无法解绑 
 	FirstPassword+" m"=FirstPassword+" n"+FirstPassword;   //失效,非报错
	cin>>FirstPassword;	 //不执行,被屏蔽,不报错 
 	cout<<SecondPassword;//此时似乎既无法改变所指对象亦无法改变值,而去掉m后无此效果 
	return 0;
}

这是一时的一个脑洞,居然可以实现string类型变量和一个字符串相加然后赋给常的string类型变量。

(如果不是常的当然是会报错。)

然后此时居然就起到了双const的效果。

3、与指针勾搭的const

这个比引用多了一层板凳那个状态,不仅有常量指针还有指针常量。



#include <iostream>
using namespace std;
int main(){
    const int a=1;
    int b=2;
    const int *p1=&b;
    int *p2=&b;    //a is error,p1 is error
    int *const p3=&b;    //a is error,p1 is error
    const int *const p4=p2;
    p1=p4;
    p2=p3;    //p4 is error
    return 0;
}

const int *p 是针对*p是常量;int *const p 是针对p是常量。

*p是常量就是相当于值是常量的情况,不能被int型指针及int *const所指向。

也就是说不强调指向常量的指针不能指向 常量或 指向常量的指针。 

可以看到不存在int 型的引用绑定了int const型对象;

不存在int 型指针(或常指针)指向了int const型对象(或指针)。   //int const==const int



内在逻辑是把赋值操作和类型判断区别开,只要能赋值,类型就变为赋值后的逻辑类型,而不受之前类型的影响;

而能否赋值由赋值对象和接收赋值一方的状态决定,原则是 int const型对象(指针)不流向int型指针(常指针)或引用。

(const int a=10; int b=a; 是完全正确的)

4、与auto

并不喜欢顶层const和底层const理论,用起来还要判断一番

一个常见的例子

int main(){
	int a=1;
	const int b=a,&c=a;
	auto d=&a;        //auto==int*
        auto e=&b;        //auto==const int*
        return 0;
}

显然,只需要根据 简化原则即可。const int a=10; *** b=a中b是否const都是对的,则auto的判断优先不加。

同时参照   int const型对象(指针)不流向int型指针(常指针)或引用 , auto选择有时加const。

int main(){
	const string str("world");
	auto &c=str;           //auto==const string
	return 0;
} 

其他同理。如引用,指针等。当然可以在auto前加const等。

5、decltype

decltype用的时候和auto不一样的在于,它前面有个括号

decltype (a) b=c; 通过a确定b的类型,而不是通过C。因此decltype就更有底气同时保留顶层const和底层const。逻辑上我们也更倾向于它如此。

关于其他方面 decltype对引用的偏执,比如

int a=1, &b=a;
decltype(b+0) c=2;  //此时是int类型

int *p=&ci;
decltype(*p)c;                                //错误,c是int&类型而非int类型,必须初始化
/*如果表达式的内容是解引用类型,将得到引用类型*/
double k=3.14;
 decltype(k=ci) e=k;		//e是double&类型,k=ci产生引用类型  
 /*赋值会产生引用类型,引用的类型是左值表达式 */ 
int a=1;
decltype((a)) b=a; // 此时b的类型是int类型的引用, b和a绑定在了一起

以及decltype如何不需要计算结果,因此不需要函数调用,而auto需要,那就是他们之间的恩怨了。

附:常量引用绑定对象时的问题

int a=1;
const int &b=a;

实际执行的操作为:

int a=1;
const int temp=a;        //temp临时变量
const int &b=temp;

常量引用只有以下情况会绑定到实际对象上:

const int a;
const int &b=a;

int a;
const int &b=a;

(是否赋值不受影响)



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值