【c++】——const详解

文章目录

    • 1、在.c中const 的用法
    • 2、在.cpp中const 的用法
    • 3、Const和static修饰的成员
      • 3.1const修改成员变量的处理
      • 3.2static修饰的成员变量
    • 4、int* const p和const int* p区别

首先,我们要来明确一下,什么是const,在我们通常的观念里面,我们会认为下面这个代码是错误的。

	const int b = 20;b = 30;

因为const修饰的变量不能作为左值。初始化完成后值不能被修改。

1、在.c中const 的用法

在我之前的一篇博文中,有对其大概的讲解,c语言中const的用法
1.1const修饰的量,可以不用初始化
例如以下的程序是错误的:

const int a;
a = 20;

因为const的值虽然可以不用初始化,但是以后就不能作为左值来进行修改了。
所以一般情况下还是对其进行初始化。

1.2const修饰的量不叫常量,叫常变量
他和变量的唯一区别就是不能够把她作为左值修改。比如下列程序就是错误的。

const int a = 20;
int array[a] = {};

1.3练习
下列.c程序,打印结果是多少?

int main()
{const int a = 20;int* p = (int*)&a;*p = 30;printf("%d %d %d\n", a, *p, *(&a));return 0;
}

在这里插入图片描述
指针指向的是a的内存。结果是30,30,30.因为a这块内存已经被改了。a一直都是一个变量

2、在.cpp中const 的用法

2.1const修饰的量叫做常量,必须初始化
所以以下代码则是正确的:

const int a = 20;
int array[a] = {};

2.2const修饰的量叫常量
还是上述.c里面练习的代码。打印结果则为20 30 20
这是因为const的编译方式不同

  • c中,const就是当做一个变量来编译生成指令的
  • c++中所有出现const常量名字的地方,都被常量的初始值替换了。尽管后期可能对其做了很多处理还是不能改变常量的值。

2.3常量值不允许被修改(这种修改包括间接修改和直接修改)
1、对于间接修改的错误示范
【栗子1】

int main()
{const int a = 10;int*p =&a;return 0;
}

在以上代码中,第二句就会报错。因为如果此时允许普通的指针指向常量内存块,以后我们要进行*p =20的操作就不对了,因为常量值不允许间接访问来修改。主要是杜绝间接访问常量内存的风险

【栗子2】

int main()
{const int a = 10;const int*p =&a;int *q = p;return 0;
}
  • 在我们之前c语言的理解方式当中,会认为第三句的转换方式涉及到const int*到int*的转换,相当于把权限扩大了,所以不对
  • 但是以c++的方式来理解,在第二句代码中const修饰的是*p,后面指向p的指针q就存在间接访问修改*p的风险。

2、对于间接修改的正确示范
【栗子1】

int main()
{int a = 10;int*p =&a;const int *q = p;return 0;
}

因为我们只从const修饰的量往下看有没有风险存在,const修饰的是*q,其间接访问就是*q有const修饰,所以没有风险存在

【栗子2】

int main()
{int a = 10;int* const p =&a;int *q = p;return 0;
}

因为const修饰的是p,p就是直接访问,这时,如果要间接访问必须就要二级以上的指针来访问,所以不存在间接访问,没有风险

3、Const和static修饰的成员

关于成员变量之前的关系,可以参考博文成员方法之间的关系

3.1const修改成员变量的处理

1、常对象不能调用普通方法
为了说清楚这个结论,我们引用一段错误的代码来加以分析。

class Test
{public: Test(int a):ma(a){}void show(){}private:int ma;};
int main()
{const Test test(10);test.show();return 0;
}

仔细分析这段代码

  • 首先生成了test这个常对象,调用show成员方法。
  • 因为在方法内部的this方法为Test* const this,const修饰的是this指针不是 *this,代表我们可以通过*this的方式来修改常量的值。这样显然是不允许的

上面的这段类里面的代码就和const对常量操作的下述代码逻辑相同。

const int a= 10;
int* const p = &a;

显然是不可以的。这个问题的解决方法就是让this指针变为const Test* const this的方式,也就是把show成员方法变为常方法

2、普通函数可以调用常方法
想要得到其理论的正确性,我们先在常量里面进行分析,普通函数调用常方法类比到变量里面的逻辑代码如下:

int a =10;
const it* const p = &a;

显然这样的表达式是正确的,类比到类里面也就是正确的。

3、常方法不能调用普通方法
基于上面两条理解一下,其实常方法里面的this指针指向的对象就是常对象,在调用print方法的时候就变成了用常对象来调用普通方法,显然这样是不行的。

4、在普通方法里面可以调用常方法

总结

  1. 常对象不能调用普通方法,常对象只能调用常方法
  2. 普通对象可以调用常方法
  3. 常方法中不能调用普通成员方法
  4. 普通成员方法中能调用常方法。

在这里插入图片描述

3.2static修饰的成员变量

首先我们写一个静态成员变量的例子,如下代码所示:

class Test
{public:Test(int b):mb(b){}void show(){std::cout<<"ma: "<

其中ma为静态成员变量,他主要有以下特点:

  1. 所属关系:成员变量不属于对象,属于类。是所有对象共享的

  2. 初始化方式:构造函数不能初始化静态的成员变量,一定要在类外初始化
    【解释】因为构造函数是初始化对象所占的内存空间的,静态成员变量都不属于对象。所以在类外进行初始化的操作如下:
    在这里插入图片描述

  3. 静态成员变量的访问:通过对象或者作用域的方式都可以。具体操作如下:
    在这里插入图片描述
    而对于静态成员方法的访问是不依赖于对象的访问,只能用作用域的方式来访问静态成员方法。
    在这里插入图片描述

  4. 静态成员方法的访问权限:因为静态成员方法是_cdecl调用约定,也就是说没有this指针的,所以不能访问普通的成员变量,可以访问全局变量和静态成员变量。

  5. 调用关系:静态成员方法不可以调用普通成员方法,但是反过来普通成员方法就可以调用静态成员方法。因为普通函数的调用是通过this指针来调动的

4、int* const p和const int* p区别

const和一级指针结合的三种情况
在c++ 的语言规范里面,我们都知道const修饰的是离他最近的类型。

情况一:

const int *p;

const修饰的是*p,表示的是可以任意指向不同int 类型的内存,但是不能通过指针间接修改指向的内存的值
所以,*p = 20错误的 p = &b正确的

情况二:

int* const p;

表示的是这个指针p现在是常量,不能再指向其他内存,但是可以通过指针解引用修改指向的内存的值
所以, *p = 20正确的 p = &b错误的

情况三:

const int *const p; 

这种情况下,不仅仅指针p是常量,指针所指向内存里面存放的值也是常量,都不允许修改。

总结:

  • const int *p这个const修饰的是p指向的内存的值不能被修改,但是p本身是可以修改的
  • int* const p这个const修饰的是p本身是个常量,不能被修改,但是p指向的内存的值是可以被修改的。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部