3.read-only的const。如果你突然冒出一句看似很高深的话但又不解释一般都是装逼,就像前面提到过const准确的应该理解为一个read-only的变量而不是一个常量,那么常量和变量的区别到底是什么呢?按照c语言的定义,比如,1.5是一个浮点数常量,”roger”这是一个字符串常量,而在C语言中(在C++语言中扩展了const的定义,不能完全使用这种理解方式),const并不是一个常量,你可以定义一个.c文件,然后使用如下的定义:

const int Length=100;
int arr[Length];

进行编译,编译器会给出类似这样的错误信息“expected constant expression”,说明编译器不认为const定义的是常量,而如果使用int arr[1]就可以通过编译。还有一个地方也可以进行证明,在c语言中,case语句里必须是常量,如果const定义的真的被认为是常量的话,那么在switch的case语句中就可以使用它,但是事实并不是这样的,在编译器中做这样的尝试之后,会给出类似如下的错误信息:“case expression not constant”。

4.类里面的const。C++作为一种面向对象的语言,可以定义类、成员函数等等是其区别于C语言的一个重大特点,const关键字在类中的使用也是有各种陷阱和容易混淆的地方的,为了配合下面的说明,我们定义一个类Mobile。

class Mobile
{
public:Mobile(){electricity=0;};void SetElectricity(int value){electricity=value;};int GetElectricity(){cout<<"non-const"<<endl;return electricity;};
private:int electricity;//电量
};

在这个类中,有一个设置电量的成员函数和一个获得电量的成员函数。但是目前这个类有个问题就是可以在Get函数中修改所要获取的值,虽然在有些情况下是可以的,但是在本类中我们的本意是完整无误获取电量,所以需要确保这一点,我们必须使用const,为了区别于返回一个const int的值的函数,C++采用的是在函数后面添加const表示该函数不能修改成员变量。为了展示这两种不同的摆放方式有什么不同,添加两个成员函数如下:

const int GetElectricity()
{cout<<"const1"<<endl;return electricity;
};int GetElectricity() const
{cout<<"const2"<<endl;return electricity;
};

这时候点击编译,一定会产生类似如下的错误信息“'GetElectricity' : redefinition; different type modifiers”,c++中,返回值不同不能区别函数的重载与否。所以编译器会认为这是两个一样的函数,所以如果这样定义一个函数其作用是返回值不可被修改。在删去该函数之后,编译通过,也就是说,在类中,可以使用const实现对于成员函数的重载,但是想要达到这一目的摆放的位置很重要。既然是重载,那么就应该在调用中体现出来,C++中是采用如下的方法调用这两个函数的,对于const的对象调用const的函数,而对于非const的对象,调用普通的函数,可以通过以下的测试代码证明:

Mobile m;
m.SetElectricity(100);
const Mobile m1;m.GetElectricity();
m1.GetElectricity();

运行结果如下:

可以看到它们的调用的函数各不相同,可以按照这个思路从编译器的角度理解一下为什么m1调用Set会产生错误,其产生错误的原因绝对不是“从逻辑上一个const的值不能被修改”,编译器完全不知道什么叫做逻辑,其判断方式是在class里面根本找不到const标示的重载函数,所以其判断为错误,我觉得写程序要时刻铭记编译器的思考方式和人的思考方式是不同的。总之,在类中,可以使用const限制成员函数对成员变量的修改,并且可以实现成员函数的重载。

      下一个问题可能稍微有些颠覆性,怎样看待一个类的const?也就是说比如m1,我们是应该认为在外部(也就是调用方)不能修改其值且在其内部也不能修改其值,或者是在外部不能修改其值但是在内部可以修改,只是让外部不要发现呢?啊,我描述的有点绕,那么我换个方式描述一下试试看。比如想象你是调用方,你并不知道这个类内部是怎样实现的,你只要能够检查到m1的内容不能随意被修改就可以认为其符合const的约定,看起来这么说在逻辑上符合对于const的要求。还有一种方法就比较严格,你要求类内部要严格自律,不是只是让外部看起来是不能被修改的,同时内部也是一丝一毫不能被修改。这两种都可以说的通,但是编译器采取的是哪种呢?机器不像人,没有拥有感情,这既是好处也是坏处,在设计的时候,其采用的是上面第二种方式,但是,所有人类都是一样,总不喜欢一直按照规矩走下去(或者说人们在制定规矩的时候都是从片面的地方,并不能想出一个全面完美的规矩),有时候可能真的需要在标示了const的成员函数中修改某一个成员变量的值,于是C++为了解决这个问题,提出了一个和const相反的关键词,mutable,只要用该关键字标示的成员变量就可以在const函数中被修改,比如将上面类添加一个新的成员函数ispoweroff,标示为mutable,用来断定是否没电了,虽然在Get里面设计这样一个内容不合逻辑,先将就着看看吧。初始为false,在标记有const的成员函数中添加如下语句:

if(electricity==0) ispoweroff=true;

使用上面一样的代码测试该程序,可以发现并没有报错,说明即使是const标记的函数仍然通过了检测,此时const的对象同样不能调用非const的函数,说明至少在外部不能察觉出const的对象内容被修改,听起来有点像中国常用走后门技术,但是这也是经常会被问到的一个问题。

5.其他有关const的内容。

const还有一些可能会被问到的问题,我印象中最多的一个是#define和const定义一个内容有什么不同,#define定义的是一个宏,定义的是一个常量,只是简单的进行替换,所以其并不能进行类型的检查,但是const定义不一定是常量(在C语言中),#define定义的内容在C语言中可以使用在数组大小,case语句中,但是const定义不能。另外,const定义的变量可以更节省内存,因为const定义的内容不会在每次赋值给某个变量时都会重新分配内存,而#define定义每次都会分配一个内存。

如何将const的强制转换成为非const,c++使const_cast<type>(expression)可以将非const的值转化成为const的值,但是这个转换指的是const指针转换成为非const指针,比如下面的代码就是错误的:

const int b=0;
int a=1;
a=const_cast<int>(b);

在给出正确的代码之前,在这个地方可以继续考察下自己有没有搞清楚上一篇说的const int*和int *const之间的差别,可以思考一下,下面哪个赋值是可以通过的?

//代码1
int i=0;
int *const  b=&i;
int* a;
a=b;
//代码2
int i=0;
int const *b=&i;
int* a;
a=b;

不能的那一组采用a=const_cast<int*>(b)就能完成转换。如果想把非const对象转换成为const对象,可以使用static_cast。

还有一个常见的就是关于iterator的,在C++中你可以定义如下两种iterator:

const vector<int>::iterator it1=...;
vector<int>::const_iterator it2=...;

这也是经常会被问到的一个地方,也就是上面两个的差别,这个正好和指针那个相反,也就是第一个不能修改其指向,但是可以修改其指向的内容(不能++操作等等),第二个是不能修改其指向的内容,但是可以修改其指向(可以参与迭代),可以参考一下上一篇的内容(初级程序员面试不靠谱指南(一)),具体原因,到写STL的时候再详细说明。

下一个我曾经遇到的问题是,为什么一般要用const修饰operator*(或者在重载操作符其余的操作符定义中)?这个设计我个人觉得很巧妙,由于const不能作为左值,所以如果定义了两个对象a,b,那么(a*b)=c这种情况就不会通过编译。

另外关于一些const的比较重要内容就是和&相关的一些,也就是我下一篇要写的内容,关于从const的内容,我推荐可以看看下面这篇文章:

http://www.cprogramming.com/tutorial/const_correctness.html

转载于:https://www.cnblogs.com/ZXYloveFR/archive/2013/05/19/3087309.html

初级程序员面试不靠谱指南(二)相关推荐

  1. 初级程序员面试不靠谱指南(一)

    "来到这英雄宴中的人物,就算本身武功不是甚高,见识也必广博,"太祖拳法"的精要所在,可说无人不知.乔峰一招打出,人人都是情不自禁的喝了一声采!这满堂大采之后,随即有许多人 ...

  2. 初级程序员面试不靠谱指南(六)

    五.很强很伟大的函数指针 我想看到这个标题中"函数指针"几个字之后,估计有一半人会选择关掉界面,因为我最开始学习C语言的时候这一章我曾无数次跳过,看到书中那些复杂的星号括号直接就崩 ...

  3. c语言闯关考试题讲解,程序员面试闯关(二):数据结构考点与细节分析

    上一篇文章程序员面试闯关(一):字符串匹配+排序+查找列举说明了各种常见的排序算法等算法基础,这里,主要分析下数据结构相关的基础和注意点. 一.线性表 1. 数组(顺序存储结构) 效率分析 查找:O( ...

  4. 初级程序员面试话术(1)

    其实我也是一个刚入行不是很久的小白,和同为初开的朋友们聊天所得,来和大家分享一下在面试的时候或者想成为java程序员的时候应该去注意些什么,首先是从简历下手,简历的好坏也决定着面试机会! 一:简历 简 ...

  5. 程序员面试不完全指南

    程序员找工作难,想要被成功聘用更难.最常见的办法是经历一次又一次的面试失败后自己琢磨出面试技巧,当然也可以花钱到一些培训机构去接受专业的书面简历 和模拟面试的指导.这些方法可能都会奏效,但是却并不是时 ...

  6. 千锤百炼始成钢之初级程序员面试总结(非技术1)

    背景 以往曾就职于计算机培训行业,也培养除了不少出色的软件工程师,记得很多刚刚出师的学员在就业面试时给我写过总结,先在就分享给大家希望对伙伴们有点启发和帮助. 正文 公元后2008年9月1日星期一,要 ...

  7. java 前置零_程序员面试必考题(二十二):Java中的前置条件和后置条件

    转载自微信公众账号:开点工作室(ID:kaidiancs) Java程序中,程序员可以使用前置条件与后置条件,来控制是否执行方法及判断方法是否正确执行. 前置条件(precondition)是一条条件 ...

  8. 程序员面试中一面、二面、三面有什么区别?

    很多公司面试都分一面.二面.三面甚至更多,大家可能会好奇,为什么要面这么多面,每一面又有啥区别呢? 首先我来回答下为什么要这么多面,最核心的是最后3点: 如果光是一个人面,担心会看走眼: 面试通过最后 ...

  9. Java基础易错面试题,初级程序员面试必看!(会不断更新)

    写在前面: 我是「扬帆向海」,这个昵称来源于我的名字以及女朋友的名字.我热爱技术.热爱开源.热爱编程.技术是开源的.知识是共享的. 这博客是对自己学习的一点点总结及记录,如果您对 Java.算法 感兴 ...

最新文章

  1. struts深入理解之登录示例的源码跟踪
  2. linux怎么查端口是否被占用,LINUX中如何查看某个端口是否被占用
  3. 基于微服务架构的token生成和使用
  4. 计算机应用基础案例教程总结,计算机应用基础案例教程
  5. 接到老大的任务,要求开发内部进销存系统
  6. Mr.J--Bootstrap使用
  7. IntelliJ IDEA 安装使用 aiXcoder 智能编程助手
  8. IT NEWS WebSite
  9. html怎么让图片自动动起来,css如何让图片动起来?
  10. 微信小程序云开发实现微信小程序订阅消息服务通知教程
  11. rtklib postpos 梳理(以单点定位为例)
  12. 手把手教你用keras搭建GAN
  13. 爬虫python创意_爬虫案例:利用python爬虫关键词批量下载高清大图
  14. 快速编程的捷径——计算机达人成长之路(40)
  15. Unity3D——学习分享(一) 游戏开发
  16. Java操作Excel之Excel文件的下载
  17. Dell6400拆卸与维护
  18. 使用python3.7.2 实现大名鼎鼎的Elo Score等级分制度 CSGO段位机制
  19. SAP中采购计划行中的原有数量的分析实例
  20. 微信公众平台开发案例

热门文章

  1. 计算机系统组成 教案,计算机系统组成教学设计.doc
  2. pyRedis - 操作指南:增/删/改/查、管道与发布订阅功能
  3. 什么是mock测试 等自己有时间好好研究一下
  4. Dubbo源码分析(三):ExtensionLoader
  5. 1.1 WEB API 在帮助文档页面进行测试
  6. Linux基础系列4(ls,cp命令详解)
  7. 判断两个ListInteger是否包含同样的值,不考虑位置关系
  8. SQLSERVER到底能识别多少个逻辑CPU?
  9. STM32F429HAL库UART学习笔记
  10. Javascript第六章世上最全常用RegExp正则表达式及表单验证源码第七课