1.const与普通变量
定义const变量:初始化完成后,值不可被修改
`
2.const与指针
相信很多人都记不清const在指针前后到底修饰什么,下面请看
int a = 5;
const int *p =&a;
*p = 20; //error 不可以通过修改所指向的变量的值
int b =20;
p = &b; //right 指针可以指向别的变量
对于const在最前面我们可以想象没有int* p,那么const是不是修饰&a,那么&a是不是就没法修改,也就是a无法修改了,但是p不受影响,p是什么,p是指针,所以p的指向还是可以改变的。
当为常量指针时,不可以通过修改所指向的变量的值,但是指针可以指向别的变量。
int a = 5;
int *const p = &a;
*p = 20; //right 可以修改所指向变量的值
int b = 10;
p = &b; //error 不可以指向别的变量
const这次在里面是不是紧靠着p,p是指针,是不是p的指向无法改变,&a是不是不受影响了,那么a就可以正常改变,你理解了么?
当为指针常量时,指针常量的值不可以修改,就是不能指向别的变量,但是可以通过指针修改它所指向的变量的值。
总结:
1.如果const位于星号的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;
2.如果const位于星号的右侧,const就是修饰指针本身,即指针本身是常量。
3.const与函数
const int fun(const int a)const;
const修饰返回值
修饰返回值 const int fun();不能修改返回值。
const修饰形参
int fun(const int x);x在函数体内无法被修改
const修饰this指针(类与对象)
请看下面的代码
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<assert.h>
using namespace std;
class Date
{
public:
Date(int year, int month,int day ,int &i)
:_year(year)
,_month(month)
,_x(1)
,_ref(i)
{
_day = day;
}
//总结一下:只读函数可以加const,内部不涉及修改成员的都是只读函数
void Print()const
{
cout << _year << '/' << _month << '/' << _day;
}
void Print()
{
cout << _year << '/' << _month << '/' << _day;
}
int& func()//int& func()返回局部变量的引用也会有问题
{
int ret;
return ret;//返回的不是ret,而是ret的拷贝,临时对象具有常性,不能修改
}
//日常自动生成就可以
//不想被取到有效地址
Date* operator&()
{
return this;
}
const Date* operator&()const
{
return this;
}
friend ostream& operator<<(ostream& out, const Date& d);//Date* this在out前面
friend istream& operator>>(istream& in, Date& d);//不能加const
private:
int _year; //每个对象的声明
int _month;
int _day;
//必须定义时初始化
const int _x;
int& _ref;
};
ostream& operator<<(ostream & out, const Date& d)//Date* this在out前面
{
out << d._year << '/' << d._month << '/' << d._day << endl;
return out;
}
istream& operator>>(istream& in, Date& d)
{
in >> d._year >> d._month >> d._day;
return in;
}
void test_date1()
{
//const Date d1(2023, 7, 27);//传着传着就有可能变成const对象,const对象不能调用
//非const函数,权限不能放大
//d1.Print();
//d1.func() = 1; error
}
//int main()
//{
// test_date1();
//}
struct SeqList
{
public:
void push_back(int x)
{
_a[_size++] = x;
}
size_t size()const
{
return _size;
}
size_t capacity()const
{
return _capacity;
}
int& operator[](size_t i)//写/读
{
assert(i < _size);
return _a[i];
}
const int& operator[](size_t i)const//只读函数
{
assert(i < _size);
return _a[i];
}
private:
int* _a = (int*)malloc(sizeof(int) * 10);
size_t _size = 0;
size_t _capacity = 0;
};
void Print(const SeqList& s)//const修饰的本质是s的成员不被修改,不是s._a里面的数据不被修改
{
for (size_t i = 0; i < s.size(); i++)
{
cout << s[i] << " ";
//s[i]++;
}
}
int main()
{
SeqList s;
s.push_back(1);
s.push_back(2);
s.push_back(3);
Print(s);
cout << endl;
return 0;
}
什么时候const修饰this呢,我们可以认为只读函数可以加const,内部不涉及修改的都是只读函数
但是为什么print函数我们要写两次呢,因为Date在其他函数调用过程或者初始化的时候成为const常量
而const对象不能调用非const函数,权限不能放大,所以就有了const版的print函数,所以我们认为只读函数最好都加上const。同理如下:
而对于第二个前面的const是因为
Print里面是const类型的形参,我们不希望s._a被改变,所以在函数前面也加了const,而operator【】函数有两个是因为一个是只读函数,而另有一个要可以修改,一个函数无法同时支持const和非const,所以写了函数重载。
调用问题:
请各位思考下面几个问题
1,3错,2,4对,因为加了const就相当于权限缩小了,所以权限小的不能调用权限大的,也就是const对象不可以调用非const成员函数,权限可以缩小,平移,但是不能放大。