const修饰变量


int main(int argc, char* argv[])
{const int b = 3;int* c = (int*)&b;*c = 5;//这里即便把b所在地址的值修改了,但后面调用b的时候,b仍然是3cout << "*c的值为:" << *c << endl;//5cout << "b的值为:" << b << endl;//3return 10086;
}

对于一个const常量,通过指针修改其值后,可以看到指向b的指针输出为5,而b依然是3,没有改变,为什么呢?

调试一下,发现并没有问题,指针指向的内容确实改变了

其实这种情况,编译器会认为b是一个在编译期就可计算出结果的常量,就像宏定义一样,用到b的地方会被编译器替换成3。即在没有通过指针修改b的值的时候,所有b的值都已经默认为3了。

假如通过一个函数的返回值给b赋值,即运行时初始化,这样b的值在编译器就无法确定了

int set_value(int i)
{return i;
}int main(int argc, char* argv[])
{const int b = set_value(3);int* c = (int*)&b;*c = 5;//这里即便把b所在地址的值修改了,但后面调用b的时候,b仍然是3cout << "*c的值为:" << *c << endl;//5cout << "b的值为:" << b << endl;//5return 10086;
}

此时,b的值也就变化了。

又知道,constexpr可以赋予常量表达式获得在程序编译阶段计算出结果的能力,上面的例子中,set_value()函数无法在编译时确定b的值,那假如我们将函数用constexpr修饰的话,是不是函数又可以在编译时期得到b的值了,进而,后面所有的b的值就又可以提前确定了,再通过指针修改b,b也不会变化了。验证一下:

确实如此。

还有一个情况,我们知道,全局常量的存储位置是数据段的全局/静态区,这个内存区是只读的,而局部常量存放于堆栈中,虽然不能直接修改,但可以通过指针间接修改。

上面的例子就是因为我们把声明为了局部变量,所以b可以通过指针被间接修改,假如把b声明为一个全局变量,那么就无法再通过指针修改其值了。

constexpr int set_value(int i)
{return i;
}
const int b = set_value(3);
//只要声明为全局变量,不管能不能在编译期获得值,都不能通过指针修改其内容
int main(int argc, char* argv[])
{int* c = (int*)&b;*c = 5;//这里即便把b所在地址的值修改了,但后面调用b的时候,b仍然是3cout << "*c的值为:" << *c << endl;//5cout << "b的值为:" << b << endl;//3return 10086;
}

补充一点:关于const和constexpr的区别

说区别,我其实都不认为二者有什么相似性,充其量有一些联系。

const是变量类型名的一部分,part of type name,一个名字叫“const T”或者“T const”的类型,和T这个类型本身处于一种平级的关系,和T不同的就在于这个类型的对象自产生后就不能再更改了。

constexpr是声明的一部分,即 part of a declaration,他不是变量类型的一部分。当他出现在一个变量的声明中时,他要求编译器在编译期间就初始化并确定下来这个变量(否则编译报错);当他出现在一个函数的声明中时,他要求至少有一条return路径可以(但不是必须)在编译中确定下来,即返回的是编译期常量。

二者的联系就在于,在使用constexpr声明一个类型为T的变量时,constexpr会自动把这个变量定义为const T类型。即constexpr在完成它本职工作(告诉编译器这是个编译期常量)的同时,还把原来的T类型改为了const T类型。这就是二者的联系。
链接:https://www.zhihu.com/question/35614219/answer/1477686611

const修饰指针

const int *ptr
int const *ptr //和上面等价
int * const ptr

* 在 const前面,则const直接修饰的指针,指针位置不能瞎动;
* 在 const后面,则const修饰的是 *ptr,则表征指针指向的这个值不能瞎动;
如形参为const A* a,则不能对传递进来的指针的内容进行改变,保护了原指针所指向的内容。
如形参为const A& a,则不能对传递进来的引用对象进行改变,保护了原对象的属性。

如果一个成员函数明确知道其不会修改数据成员,那么最好将其声明为const,因为const成员函数中不允许对数据成员进行修改,如果修改,编译器将报错,这大大提高了程序的健壮性。

如果输入参数采用“值传递”,由于函数将自动产生临时变量用于复制该参数,该输入参数本来就无需保护,所以不要加const修饰。
例如不要将函数void Func1(int x) 写成void Func1(const int x)。同理不要将函数void Func2(A a) 写成void Func2(const A a)。其中A为用户自定义的数据类型。

对于非内部数据类型的参数而言,像void Func(A a) 这样声明的函数注定效率比较底。因为函数体内将产生A类型的临时对象用于复制参数a,而临时对象的构造、复制、析构过程都将消耗时间。
为了提高效率,可以将函数声明改为void Func(A &a),因为“引用传递”仅借用一下参数的别名而已,不需要产生临时对象。但是函数void Func(A &a) 存在一个缺点:“引用传递”有可能改变参数a,这是我们不期望的。解决这个问题很容易,加const修饰即可,因此函数最终成为void Func(const A &a)。
以此类推,是否应将void Func(int x) 改写为void Func(const int &x),以便提高效率?完全没有必要,因为内部数据类型的参数不存在构造、析构的过程,而复制也非常快,“值传递”和“引用传递”的效率几乎相当。

const修饰函数

const可以修饰类成员函数,防止类成员函数中除了static成员之外的其他成员被修改。

在类中将成员函数修饰为const表明在该函数体内,不能修改对象的数据成员而且不能调用非const函数。为什么不能调用非const函数?因为非const函数可能修改数据成员,const成员函数是不能修改数据成员的,所以在const成员函数内只能调用const函数。即便某个非const成员函数没有改变成员变量,也不能被const成员函数调用。

下图是另一种情况,当类对象指针作为const形参时,只能通过指针调用const成员函数

class people
{int private_val_1;
public:String name;int age;int high;bool sex;
public:people(){}people(String name, int age, int high, bool sex){this->name = name;this->age = age;this->high = high;this->sex = sex;}void Rename(String name){this->name = name;}void Printname() const{//const表示此成员函数不允许修改成员变量//也不允许调用其他有修改成员变量权限的成员函数(即非const成员函数)cout << name << endl;cout << age << endl;cout << high << endl;cout << sex << endl;}
};void fun(people* in)
{in->age++;//可以调用和修改所有公有变量,因为形参没有const限制//可以调用所有成员函数,因为形参没有const限制
}void fun2(const people* in)
{in->age;//可以调用所有公有变量in->age++;//错!不可以修改变量in->Printname();//虽然有const限制,但仍然可以调用没有修改成员变量权限的成员函数in.Rename();//错!此成员函数没有const限制,有修改成员变量的权限people* temp = new people();in = temp;//可以修改
}void fun3(people* const in)
{in->age++;//大部分都和fun2相同//区别如下:不能修改in的指向了people* temp = new people();in = temp;//这样就错了}

C++:const修饰变量、形参、函数相关推荐

  1. C语言 const 修饰变量 - C语言零基础入门教程

    目录 一.const 简介 二.const 实战 1.使用 const 修饰变量必须初始化 2.使用 const 修饰变量不初始化 3.修改 const 修饰变量的值 三.重点提示 四.猜你喜欢 零基 ...

  2. 初识C语言之——static修饰变量及函数的认知。

    static--C语言中考题常见的关键字 在c语言中:static是用来修饰变量和函数. 我们可以先从字面意思来理解,即"静态的,静止的". 以至于它的修饰作用就有如下三个作用. ...

  3. const 修饰变量

    const 修饰变量 const修饰变量 该变量成为常变量,不能被修改. 例一:const修饰一般变量(以整型变量为例) const int num = 100; int* p = # num = 2 ...

  4. C语言static关键字修饰变量及函数时的用法和原理

    目录 一.static关键字修饰局部变量 二.static关键字修饰全局变量 三.static关键字修饰函数 一.static关键字修饰局部变量 在内存中,往往将其分为三个区块,栈区,堆区,静态区.C ...

  5. C++基础08-this指针-const修饰成员函数-函数返回引用/值

    一.this指针 1.C++类对象中的成员变量和成员函数是分开存储的.C语言中的内存四区模型仍然有效! 2.C++中类的普通成员函数都隐式包含一个指向当前对象的this指针. 3.静态成员函数.成员变 ...

  6. const 修饰函数参数,返回值,函数体,保护数据

    一.const 介绍 1.const 定义 const 修饰的数据类型是指常类型,常类型的变量或对象的值是不能被更新的. 2.const 目的 const 推出的初始目的,正是为了取代预编译指令,消除 ...

  7. const 修饰函数参数,返回值,函数体

    看到const 关键字,C++程序员首先想到的可能是const 常量.这可不是良好的条件反射.如果只知道用const 定义常量,那么相当于把火药仅用于制作鞭炮.const 更大的魅力是它可以修饰函数的 ...

  8. C语言 const 修饰函数参数 - C语言零基础入门教程

    C语言 const 修饰函数参数 - C语言零基础入门教程 目录 一.const 简介 1.const 修饰变量 2.const 修饰指针 3.const 修饰在函数名前面 4.const 修饰在函数 ...

  9. C语言 const 修饰函数返回值 - C语言零基础入门教程

    目录 一.const 简介 1.const 修饰变量 2.const 修饰指针 二.const 修饰在函数名前面 三.const 修饰在函数名后面 四.猜你喜欢 零基础 C/C++ 学习路线推荐 : ...

最新文章

  1. 基于HTML5实现3D热图Heatmap应用
  2. 网络营销外包——网络营销外包专员如何做好网站搜索引擎优化
  3. python程序员发展-Python程序员的进化史
  4. Java对象初始化顺序
  5. Spring 5 新增全新的reactive web框架:webflux
  6. window 内核详尽分析
  7. 计算机会计课程试题及答案,会计电算化课后简答题及答案.doc
  8. 终端安全 | 全面适配国产系统,打造政企合规终端
  9. Windows 程序基础
  10. [SAP ABAP开发技术总结]选择屏幕——各种屏幕元素演示
  11. edius裁剪快捷键_edius5.0常用快捷键 edius快捷键使用大全
  12. 日语---之百度百科
  13. 【修改源码】hadoop 3.3.1 failed with status code 401 Response message: Authentication required
  14. no ip domain lookup
  15. C语言程序设计专栏索引
  16. 飘云QQ宣布终止后续开发 称不懂游戏规则玩不起
  17. 【第42期】游戏策划:如何让游戏帮助孩子成长?
  18. 爱运动的人身体都不差----基于墨刀原型工具的健康软件设计
  19. python计算器gui设计_Python 计算器界面设计
  20. 面试题61. 扑克牌中的顺子

热门文章

  1. 蚂蚁集团技术专家山丘:性能优化常见压测模型及优缺点
  2. Docker 架构原理及简单使用
  3. JEECG开源团队招募新成员 2014年
  4. 自动化集成:Pipeline整合Docker+K8S
  5. 敏捷实践的价值观和方法论
  6. docsify神奇的文档网站生成工具
  7. Nuxt --- 也来说说vue服务端渲染
  8. 【转】mysql锁表解决方法
  9. 园友们大家好,我是“一只酷酷的恺”
  10. PB开发境界 多个DW进行update