目录
1. 常量指针:const int* 和int const *
C语言中的用法
一、修饰普通变量
const int 和 int const在修饰普通的变量类型(除指针)作用是相同的。
如下a,b都是int型常量,不能被修改。
int const a=5;
const int b=10;
二、修饰指针
1. 常量指针:const int* 和int const *
只要const位于*的左侧,无论它在类型名的左边或右边,都声明了一个指向对象的指针,叫做常量指针。
int a=10;
int *q=&a;
const int *p=&a;
定义一个变量a,q是一个普通的指向a的指针,p则是常量指针。这两者有什么区别呢?
普通指针q可以修改a,而对于指针p,不管他指向的是常量还是变量,在常量指针眼中都是常量,都是不可修改的。也就是说常量指针是不能修改指向对象的值的指针。
常量指针的本质还是指针,可以指向任何变量或常量,也可以更改指向对象,但是不管指向谁,他都不能去修改那个指向对象的值。
2.指针常量:int * const
声明方式:
int a;
int* const p = &a; //const放在指针声明操作符的右侧
只要const位于指针声明操作符右侧,就表示声明的对象是一个常量,且它的内容是一个指针,也就是一个地址。
上面的声明可以这么读:声明了一个常量p,它的值是变量a的地址(变量a的地址就是指向变量a的指针)。
指针常量是一个常量,在声明的时候一定要赋初始值。一旦赋值,这个常量再也不能被修改。
指针常量可以通过本身的指针特性去修改指向的对象。
指针常量是将一个常量(常量的值是地址)与一个对象锁定,一个指针常量绑定了一个对象后,就无法再更改,但是这个指针常量拥有和对象一样的权限,可以修改对象,也就是说他们现在合为一体了。其实这就是引用:引用的本质就是一个指针常量。
关于引用:https://blog.csdn.net/qq_21989927/article/details/107447970
推荐:指针常量、常量指针【const int和int const】【const int *和int const*和int* const】
三、修饰函数参数
1、防止修改指针指向的内容 【常量指针】
#include<iostream>
using namespace std;
void show_a_b(const int *a,int *b){
a[1]=100;
b[1]=100;
for (int i=0; i<4; i++)
cout<<a[i]<<" "<<b[i]<<endl;
}
int main() {
int a[100]={1,2,3,4};
int b[100]={1,2,3,4};
show_a_b(a,b);
return 0;
}
我们的本意是输出a,b数组的内容,不会通过指针来修改数组内容。同样是在中间不小心修改了数据,const修饰a,会查出错误报错,而b则不会,所以常量指针参数可以增强函数的健壮性。
2、防止修改指针指向的地址 【指针常量】
void swap ( int * const p1 , int * const p2 )
指针p1和指针p2指向的地址都不能修改。
四、修饰函数的返回值
如果函数的返回值是一个指针,我们希望这个返回值(指针)不能被修改,我们可以用常量指针的方法修饰函数返回值。
例如函数
#include<iostream>
using namespace std;
const int* add(int *a){
*a=*a+10;
return a;
}
int main() {
int b=1000;
int *p=&b;
const int *q=add(p); //调用
cout<<*q<<endl;
return 0;
}
如直接调用函数 int *q=add(p); 是错误的,会报错,因为程序认为你可能会通过q指针来修改返回值(指针)指向的数据。
正确的用法是: const int *q=add(p);
这样可以通过在函数返回值前加const来实现让函数调用时也必须加const,都成为常量指针,不能通过指针修改数据,进而保证了数据的安全。
另外,用指针常量修饰函数返回值是无意义的,因为函数返回时原来就是一对一的复制过程,不会改变指向对象。如下:x
int* const find();
C++中的用法
一、包括C语言的所有用法
上述一二三四都包括。
二、修饰类的成员函数:常函数
const修饰类的成员函数,使其只能读取数据成员变量,不能改变数据成员变量。
如果在编写const成员函数时,不慎修改了数据成员,或者调用了其它非const 成员函数,编译器将指出错误,提高程序的健壮性。所以,任何不会修改数据成员(即函数中的成员变量)的函数都应该声明为const 类型。
如以下程序中,类stack 的成员函数GetCount 仅用于计数,从逻辑上讲GetCount 应当为const 函数。
class Stack{
public:
void Push(int elem);
int Pop(void);
int GetCount(void) const; // const 成员函数
private:
int m_num;
int m_data[100];
};
int Stack::GetCount(void) const{
++ m_num; // 编译错误,企图修改数据成员m_num
Pop(); // 编译错误,企图调用非const 函数
return m_num;
}
const 成员函数的声明看起来怪怪的:const 关键字只能放在函数声明的尾部,大概是因为其它地方都已经被占用了。
三、修饰类的对象:常量对象 常对象
1.常对象只能访问成员变量的值,不能修改。
2.常对象只能调用常函数,不能调用其他成员函数。
3.用mutable修饰的数据成员,任何情况下都可修改。
#include<iostream>
using namespace std;
class Person {
public:
Person() {
m_A = 0;
m_B = 0;
}
void ShowPerson() const {
//this->m_A = 100; //const修饰成员函数,表示成员变量不能修改,除了mutable修饰的变量
this->m_B = 666;
cout<<"修改成功"<<endl;
}
void MyFunc(){
cout<<"FUCK"<<endl;
}
int m_A;
mutable int m_B; //可修改 可变的
};
int main() {
const Person person; //常量对象
cout << person.m_A << endl;
//person.m_A = 100; //常对象不能修改成员变量的值,但是可以访问
person.m_B = 100; //但是常对象可以修改mutable修饰成员变量
//常对象访问成员函数
//person.MyFunc(); //常对象只能调用常函数
person.ShowPerson();
return 0;
}
总结:
对于非内部数据类型的输入参数,应该将“值传递”的方式改为“const 引用传递”,目的是提高效率。例如将void Func(A a) 改为void Func(const A &a)。
对于内部数据类型的输入参数,不要将“值传递”的方式改为“const 引用传递”。否则既达不到提高效率的目的,又降低了函数的可理解性。例如void Func(int x) 不应该改为void Func(const int &x)。
若类的成员函数若不涉及修改成员变量,则最好用const修饰成员函数,以增加程序的健壮性。
凡希望保证数据成员不被改变的对象,可以声明为常对象。
mutable修饰的变量可以随意修改。