本文是对const关键字的一个简单总结,测试环境IDE的是Xcode13.2.1
一、const及常量指针、指针常量、常指针常量
const是常量的意思,表示被修饰的变量不可修改
如果修饰的是类、结构体(的指针),其成员也不可以更改
先说结论:const修饰的是其右边的内容
验证:
#include <iostream>
using namespace::std;
//以下使用结构体验证(类与结构体的差异在C++中,只是访问权限的不同)
struct Date {
int year;
int month;
int day;
};
int main(int argc, const char * argv[]) {
// insert code here...
const int age = 10;
//int *a = &age; //“const int *”类型不能初始化“int *”类型
//age = 20; //const修饰的变量不能修改
//const int age1; //const修饰的类型必须在初始化时进行赋值
Date date1 = {2021, 1, 2};
const Date date2 = {2022, 2, 3};
//date2 = date1; //const修饰的结构体本身不能被赋值
//date2.year = 2019;//const修饰的结构体成员不能被赋值
const Date *p = &date1;
cout << "ori:" << p->year << p->month << p->day << endl;
//p->year = 2011; //const修饰的是指针p,那么指针p即*p是不能改变的,但是p是可以修改的
//(*p).month = 4;
//*p = date2;
p = &date2;
cout << "modify:" << p->year << p->month << p->day << endl;
//Date *date3 = &date2;//'const Date *'类型不能初始化'Date *'类型
//与int *a = &age;同理
int height = 10;
int money = 20;
{
int *pp = &height;
*pp = 30; //height = 30;
pp = &money;
*pp = 40; //money = 40;
}
cout << "height:" << height << endl;
cout << "money:" << money << endl;
const int *p0 = &height;
int const *p1 = &height; //变量类型和const可以交换, p0和p1没有区别
{
const int *pp0 = &height;
//*pp0是常量,pp0不是常量,常量指针
cout << *pp0 << endl; //10
//*pp0 = 50;//Read-only variable is not assignable
pp0 = &money;
cout << *pp0 << endl; //20
}
int * const p2 = &height;
{
int *const pp2 = &height; //pp2是常量,*pp2不是常量,指针常量
*pp2 = 60; //height = 30;
//pp2 = &money; //Cannot assign to variable 'pp2' with const-qualified type 'int *const'
}
cout << "height:" << height << endl;
cout << "money:" << money << endl;
const int * const p3 = &height;
int const * const p4 = &height;
//p3和p4等价
{
const int * const pp3 = &height;
//第一个const修饰*pp3,*pp3的内容不能改 *pp3是常量,常量指针
//第二个const修饰pp3,pp3的内容不能改 pp3也是常量,指针常量,常指针常量
//*pp3 = 70;//Read-only variable is not assignable
//pp3 = &money;//Cannot assign to variable 'pp3' with const-qualified type 'const int *const'
}
return 0;
}
问题:
以下五个指针分别是什么含义?
const int *p0 = &height;
int const *p1 = &height;
int * const p2 = &height;
const int * const p3 = &height;
int const * const p4 = &height;
参考答案:
p0和p1等价,是常量指针
p2是指针常量
p3和p4等价,是常指针常量
二、const Reference常引用
前提
引用的本质就是指针,只是编译器弱化了它的功能,所以引用就是弱化了的指针
引用可以被const修饰,这样就无法通过引用修改数据了,可以称为常引用
const必须写在&符号的左边,才算是常引用
const引用的特点
- 可以指向临时数据(常量、表达式、函数返回值等)
- 可以指向不同类型的数据
- 作为函数参数时(此规则也适用于const指针)
可以接收const和非const实参(非const引用,只能接收非const实参)
可以跟非const引用构成重载
了解:
当常引用指向了不同类型的数据时,会产生临时变量,即引用指向的并不是初始化时的那个变量(汇编)
#include <stdio.h>
#include <iostream>
using namespace::std;
int test1() {
return 100;
}
//这里sum参数要求必须是引用类型
//引用接收的是变量
int sum(int &v1, int &v2) {
cout << "sum(int &v1, int &v2)" << endl;
return v1 + v2;
}
//引用变成常引用就可以接收常量了,常引用可以接收变量和常量
int sum(const int &v1, const int &v2) {
cout << "sum(const int &v1, const int &v2)" << endl;
return v1 + v2;
}
//以上两个sum函数构成重载,换成*指针也使用,去掉引用或指针就报错
int main(int argc, const char * argv[]) {
// insert code here...
int age = 10;
int height = 10;
int &ref = age; // ref相当于age的别名,ref作为引用不能再指向其他变量(即不能当其他变量的别名)
//&ref = height;
ref = 20;
cout << "age:" << age << endl << "ref:" << ref << endl;
//常引用
const int &ref2 = age;
//int const &ref2 = age; //等价上一句
//ref2 = 30; //不能再赋值
cout << "ref2:" << ref2 << endl;
//int & const ref3 = age;//Xcode报错:'const' qualifier may not be applied to a reference//'const'不能修饰引用 //VS编译器 可以编译通过 但因为引用指向本身不可更改,所以这里的const没有意义,等价于int &ref3 = age;
//int *const p3 = &age;
//p3是常量,p3不能修改,*p3可以修改即可以通过p3间接修改
//可以把引用当做指针来看,所以在VS中可以ref间接修改,本来就是间接修改,所以没意义,可能是这个原因所以Xcode编译器直接报错
//ref3 = 40;
//int &ref4 = 10; //默认引用指向变量,因为本质是指针
const int &ref5 = 10; //常引用可以指向临时数据(常量)
int a = 1;
int b = 2;
const int &ref6 = a + b; //常引用指向表达式
const int &ref7 = test1(); //常引用指向函数返回值
const double &ref8 = age; //常引用指向了不同类型的数据
cout << sum(a, b) << endl; //v1引用a
//sum(10, 20); //v1引用10?
//v1引用10的话,形参必须是const int &v1
cout << sum(10, 20) << endl;
const int c = 3;
const int d = 4;
cout << sum(c, d) << endl;
age = 30;
cout << "age:" << age << "ref2:" << ref2 << endl;
//引用的本质是指针,age变了,别名也变
//输出age:30ref2:30
cout << "age:" << age << endl << "ref8:" << ref8 << endl;
//输出age:30ref2:20,ref8指向不同数据类型产生临时变量
return 0;
}
三、const成员
const成员:被const修饰的成员变量、非静态成员函数
const成员变量:
必须初始化(类内部初始化),可以在声明的时候直接初始化赋值
非static的const成员变量还可以在初始化列表中初始化
const成员函数(非静态):
- const关键字写在参数列表后面,函数的声明和实现都必须带const//限制修改(非静态)成员变量
- 内部不能修改非static成员变量
- 内部只能调用const成员函数,static成员函数
- 非const成员函数可以调用const成员函数
- const成员函数和非const成员函数构成重载
- 非const对象(指针)优先调用非const成员函数
- const对象(指针)只能调用const成员函数、static成员函数
class Car {
public:
const int m_price = 0;
Car(): m_price(0) {}
void display() const {
cout << "price is " << m_price << endl;
}
void run() const;
};
void Car::run() const {
cout << "Car::run()" << endl;
}
四、类型转换
static_cast<type>(expression)
//对比dynamic_cast,缺乏运行时安全检测
//不能交叉转换(不是同一继承体系的,无法转换)
//常用于基本数据类型转换、非const转成const
dynamic_cast<type>(expression)
//一般用于多态类型的转换,有运行时安全检测
reinterpret_cast<type>(expression)
//属于比较底层的强制转换,没有任何类型检查和格式转换,仅仅是简单的二进制数据拷贝
//可以交叉转换
//可以将指针和证书互相转换
const_cast<type>(expression)
//一般用于去除const属性,将const转为非const
网友评论