const的3种用法:
1. 常量指针
2. 指向常量的指针(而不是什么“指针常量”)
关于1和2 黑马程序员上讲的不对。我重新看了C++ primer,进行了更正。
3. 指针and常量
#include <iostream>
using namespace std;
int main()
{
int a=10;
int b=20;
//1.常量指针(从右向左读) 说明指针是常量 也即指针存的那个地址是常量 而不是地址指向的值是常量
int *const p1=&a;
//p1=&b;//p1不可以变
*p1=20;//*p1可以变
//2.指向常量的指针 指针指向的*p不可以变
const int *p2=&a;
//*p2=30;*p2不可以变
p2=&b;//p2可以变
//3.修饰 指针and常量 俩都不能变
const int* const p3=&a;
//*p3=30;*p3不可以变
//p3=&b;p3不可以变
return 0;
}
引用的本质:
引用在C++里的实现本质其实就是上述第二种,也即指针常量。
我们可以看一下,内部是怎么实现的:
我们写的代码:
int a = 10;
int &b = a;//b是a的别名,也即对a的一个引用
b = 20;//a和b都变成20
本质上,C++编译器解释出来的代码:
int a = 10;
int* const b = &a;
*b = 20;
带来的性质:
- 由于有个const,所以p指向一旦引用之后就不能变成对其它变量的引用,如:
int a = 10, c = 20;
int& b = a;//b是a的引用
b = c;//这句话并不是说b变成c的引用了,而是a、b、c全变成20
- 引用与指针的区别:引用不可以为空(一开始初始化的时候就要赋值,而指针可以一开始为NULL)
- 常量引用的用途:用来修饰形参,防止误操作。
①比如,如果不进行常量引用,是不能int &b = 10
的:
int a = 10;
// int &b = 10; 不可以!因为引用只能对四区(栈区、堆区、全局区、代码区)中的栈区、堆区进行操作,而10是个常量,在全局区中)
int &b=a;//可以,a是局部变量,会在栈区
②但是,如果进行常量引用,在int 前加一个const变成const int &b = 10
就正确,这里正确只是因为编译器解释的时候内部自主解释成int temp = 10; const int &b = temp
。
此处多说一句:正因为int& b = 10
不正确,const int& b =10
正确,所以void func(int b){}
和void func(const int& b){}
才可以重载。且,重载的调用:func(10)
调用的是void func(const int& b)
,而 int b = 10;func(b);
调用的是 void func(int b)
引申-
1.常量引用用于形参:
void showValue(const int& a)
{
//不可以a=1000;因为有防止误操作的const
cout<<a<<endl;
}
int main()
{
int a=10;
showValue(a);
return 0;
}
2.const修饰成员函数:成员函数后加const为常函数,不可以修改不含mutable的成员属性。
#include <iostream>
using namespace std;
class Person
{
public:
int age;
void ShowAge() const
{
age=3;
}
};
int main()
{
Person p;
p.ShowAge();
return 0;
}
成员函数ShowAge()后加了const,函数中不能调用成员变量age,所以代码报错。
内在原因:
每次成员函数中用到成员变量时,编译器都会自动加上一个this指针,如上方的age变为this->age。this指针的本质是指针常量Person* const this,即*p可以修改,但是p的指向不可以修改,所以p->age不可以修改。
3.常对象:常对象只能调用常函数,成员对象前加const为常对象,不可以修改不含mutable的成员属性
#include <iostream>
using namespace std;
class Person
{
public:
Person()
{
}
int m_A;
mutable int m_B;
void func1()const
{
}
void func2()
{
}
};
int main()
{
//常对象只能改mutable的成员变量
const Person p;
p.m_B=50;
//常对象不可以改非mutable的成员变量如p.m_A=0;
//常对象可以调用常函数如p.func1();
p.func1();
//常对象不可以调用非常函数如p.func2();
return 0;
}