C++ const限定符的简述

众所周知,当我们需要一个不会被改变的变量时,我们可以运用const关键字对变量进行定义。

  • 他可以保护被修饰的东西,防止意外的修改,增强程序的健壮性
  • 也可以节省空间,避免不必要的内存分配

一、const对全局变量和局部变量的定义

const可以出现在全局区对变量的定义,也可以出现在函数体内即在栈区去变量的定义。

#include <iostream>
const int a = 10;
int main() {
	int b = 10;
	const int i = 5;
	const int* ptr1 = &i;
	int* const ptr2 = &b;
    return 0;
}

二、const修饰函数 

2.1 修饰函数参数

        const修饰函数参数,表示参数不可变

        当参数为引用时,由于引用参数传入会对实参进行改变,有可能在函数体内会改变传入的值,此时const的效果就十分明显了,我们可以通过对形参用const修饰来保证传入的参数并不会在函数体内改变。若参数为引用,可以增加效率(引用传递而不用值拷贝)

        使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作; 而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量的 副本;如果传递的是对象,还将调用拷贝构造函数。因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好。

void print(const int i)
{
	//i ++;//试图改变const修饰的函数形参将会报错
	std::cout << i<<std::endl;
}

 2.2修饰函数返回值

  •         如果函数返回值采用“值传递方式”,假如函数的返回值为一个int 类型的值,这个只是个临时的值,没有必要用const 修饰,最终这个值会复制给接受它的变量。
  •         如果给以“指针传递”方式的函数返回值加const 修饰,那么返回值可以是指针常量,也可以是常量指针。如果返回值为指针,加上const修饰之后,同样的内容是不能修改的。不过有一点需要注意,接受的变量也必须是const 修饰
  •         也可以是修饰返回值时引用的情况
const int* get(int a)
{
	return &a;
}
const int* ptr = get(i);

三、在类内对成员变量和成员函数的修饰

3.1对成员变量的修饰

        表示成员变量不能被修改,同时只能在初始化列表中赋值

3.2对成员函数的修饰

        const 修饰的成员函数为了保护成员变量,要求const 函数不能修改成员变量,否则编译会报错,也不允许调用非const函数,。声明的时候const放在函数最后

class Person {
private:
	const int m_age;
	int m_height;
public:
	Person(int age,int height) :m_age(age),m_height(height) {
		std::cout << "构造函数对常成员变量赋值" << std::endl;
	}
	int get_age()const
	{
		return this->m_age;
	}
	int get_height()
	{
		return this->m_height;
	}
	int get_error()const
	{
		return get_height();//报错,企图在常成员函数中调用普通函数
	}
};

四、const修饰类对象 

对象的任何成员都不能被修改,const类对象只能调用const成员函数

const Person xiaoming(19, 180);
	xiaoming.get_error();
	xiaoming.get_height();//报错,常对象只能调用常成员函数

五、顶层const和底层const

顶层const(top-level const)表示指针本身是个常量    int* const ptr=&m;

此时指针不可以发生改变,但是指针所指向的对象值是可以改变的

底层const(low-level const)表示指针所指的对象是常量    const int* ptr=&m;

此时指针可以发生改变,但是指针所指向的对象值是不可以改变的

顶层const可以表示任意的对象是常量(指针、引用、int、double都可以)

于是只有指针和引用等复合类型可以是底层const

执行对象的拷贝构造时,常量是顶层const还是底层const差别明显

顶层const并不会有任何影响

进行拷贝操作的时候,仅仅只是从右值(顶层const)拷贝一个值并给自己赋值,虽然右值是一个不可变的量,但是貌似对我自己的拷贝完全没有影响吧

    const int m = 10;
    int n = m;
	int* const ptr2 = &n;
	int* ptr3 = ptr2;

 上面的代码都是可行的;

但是底层const的影响是不可以忽视的;

当执行对象的拷贝操作时,拷入和拷出的对象必须具有相同的底层const资格,或者两个对象的数据类型必须能够转换

    const int* ptr4 = &i;
	const int* ptr5 = ptr4;//可行
	int* ptr6 = ptr4;//报错,由于拷出是底层指针,所以拷入必须是底层指针
	int* const ptr7 = ptr4;//报错,由于拷出是底层指针,所以拷入必须是底层指针

也很好理解嘛,毕竟底层const代表的并不仅仅只是变量本身,他是代指的变量是不能变动的,对于类型的匹配就不是表面的拷贝了,而是类型的转化。

六、const的引用(常量引用)

我们把const修饰的引用称为”常用引用“,常量引用不能直接修改所引用的对象

const int ci = 1024;//ci是一个int型的常量
const int &r1 = ci;//正确,r1是一个常量引用,并且r1本身也是一个常量
r1 = 42;//错误,引用被const限制了,不能修改所引用对象的值了
int &r2 = ci;//错误,试图让一个非常量引用指向一个常量对象

非常量引用无法指向常量对象;如果可以,我们就可以通过改变引用来改变常量对象的值,这很明显是不允许的

常量引用可以指向非常量对象;但不可以通过引用去改变对象值

  • 初始化常量引用时允许用任意表达式作为初始值,允许为一个常量引用绑定非常量对象、字面值,甚至是一个一般表达式
int i = 42;
const int &r1 = i;     //允许讲const int&绑定到一个普通int对象上
const int &r2 = 42;    //正确,r2是一个常量引用
const int &r3 = r1 * 2;//正确,r3是一个常量引用
int &r4 = r1 * 2;      //错误,右边是常量而左边并不是常量

七、指针的const

 上述通过顶层const和底层const已经将指针的const给表述了,只是有一点还需要再提一下

和引用一样,不可以用普通指针指向常量对象,不然可以轻易改值的

指向常量的指针也没有规定其所指向的对象的一定是一个常量,这就和引用可以说是一模一样了

他们都只是自己觉得自己是const而不去改变所指向或是所引用对象的值而已啦

C++禁止将const 地址赋给非const 的指针。如果非要这样做,可以通过const_cast 强制转换。

	int n = 10;
	const int* ptr = &n;//diceng
	int* ptr2 = nullptr;
	//ptr2 = ptr;//报错,不能将常量指针赋值给普通指针
	ptr2 = const_cast<int*>(ptr);//可行

 这其实就是底层const指针在从中的作用了,不理解还需移步去看第五节

const_cast虽然好用,但是还是破坏了结构的平衡,别人本来就为了不让你改变他的值才给她定义为const,你这下倒好,又把他变回来了。逗乐哈。

八、constexpr

实际开发中,我们经常会用到常量表达式。以定义数组为例,数组的长度就必须是一个常量表达式:

// 1)
int url[10];//正确
// 2)
int url[6 + 4];//正确
// 3)
int length = 6;
int url[length];//错误,length是变量

数组长度用变量表现明显是错误的,那我们有么有什么办法让他变成一个常量呢;

这就是我们的constexpr关键字的最大作用

constexpr int num = 1 + 2 + 3;
int url[num] = {1,2,3,4,5,6};

这样子就可以啦为什么需要constexpr ?——极致的性能追求

非常量表达式只能在程序运行阶段计算出结果;
而常量表达式的计算往往发生在程序的编译阶段,这可以极大提高程序的执行效率,因为表达式只需要在编译阶段计算一次,而不再需要每次运行时都计算一次。


所以,constexpr 使常量表达式获得在程序编译阶段计算出结果的能力,而不必等到程序的运行阶段。

先写到这里吧,参考了《C++ prime》《Effective C++》和一些博主的文章,后期有其他的想法在进行补充

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

听风逝夜al

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值