1什么是const?

(const类型)常类型是指使用类型修饰符const说明的类型,常类型的变量或对象的值是不能被更新的。(但可以偷梁换柱进行更新)

2为什么引入const?

const 推出的初始目的,正是为了取代预编译指令,消除它的缺点,同时继承它的优点。

3主要作用

)可以定义const常量,具有不可变性。

例如:const int Max=100; int Array[Max];

)便于进行类型检查,使编译器对处理内容有更多了解,消除了一些隐患。

例如: void f(const int i) { .........} 编译器就会知道i是一个常量,不允许修改;

)可以避免意义模糊的数字出现,同样可以很方便地进行参数的调整和修改。同宏定义一样,可以做到不变则已,一变都变!

)中,如果想修改Max的内容,只需要:const int Max=you want;即可!

)可以保护被修饰的东西,防止意外的修改,增强程序的健壮性。还是上面的例子,如果在函数体内修改了i,编译器就会报错;

例如: void f(const int i) { i=10;//error! }

)可以节省空间,避免不必要的内存分配。例如:

#define PI 3.14159 //常量宏

const double Pi=3.14159; //此时并未将Pi放入RAM中 ......

double i=Pi; //此时为Pi分配内存,以后不再分配!

double I=PI; //编译期间进行宏替换,分配内存

double j=Pi; //没有内存分配

double J=PI; //再进行宏替换,又一次分配内存!

const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干个拷贝。

)提高了效率。

编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。

4 const怎样限定内容

限定变量时:

例:下面的代码编译器会报一个错误,请问,哪一个语句是错误的呢?

typedef char * pStr;

char string[4] = "bbc";

const char *p1 = string; //1式

const pStr p2 = string; //2式

p1++;

p2++;

答案与分析:

问题出在p2++上。

const使用的基本形式: const type m;限定m不可变。替换基本形式中的m为1式中的*p1,替换后const char *p1;限定*p1不可变,当然p1是可变的,因此问题中p1++是对的。替换基本形式中的type为2式中的pStr,替换后const pStr m;限定m不可变,题中的pStr就是一种新类型,因此问题中p2不可[1]变,p2++是错误的。

const只修饰其后的变量,至于const放在类型前还是类型后并没有区别。如:const int a和int const a都是修饰a为const。一个简单的判断方法:指针运算符*,是从右到左,那么如:char const * pContent,可以理解为char const (* pContent),即* pContent为const,而pContent则是可变的。

int const * p1,p2;

p2是const;(*p1)是一整体,因此(*p1)是const,但p1是可变的。int * p1,p2只代表p1是指向整型的指针,要表示p1、p2都是指针是需写成int * p1,* p2。所以无论是* const p1,p2还是const * p1,p2,里面的*都是属于p1的。

int const * const p1,p2;

p2是const,是前一个const修饰的,*p1也被前一个const修饰,而p1被后一个const修饰。

int * const p1,p2;

p1是const,(* const p1)是整体,所以const不修饰p2。

指针指向及其指向变量的值的变化

const在*的左边,则指针指向的变量的值不可变;在*的右边,则指针的指向不可变。简记为"左定值,右定向"。

1)指针指向的变量的值不能变,指向可变

int x = 1;

int y = 2;

const int* px = &x;

int const* px = &x; //这两句表达式一样效果

px = &y; //正确,允许改变指向

*px = 3; //错误,不允许改变指针指向的变量的值

2)指针指向的变量的值可以改变,指向不可变

int x = 1;

int y = 2;

int* const px = &x;

px = &y; //错误,不允许改变指针指向

*px = 3; //正确,允许改变指针指向的变量的值

3)指针指向的变量的值不可变,指向不可变

int x = 1;

int y = 2;

const int* const px = &x;

int const* const px = &x;

px = &y; //错误,不允许改变指针指向

*px = 3; //错误,不允许改变指针指向的变量的值

以 const 声明的变量的指针只能分配给同时声明为 const的指针。

// constant_values4.cpp
#include <stdio.h>
int main() {
const char *mybuf = "test";
char *yourbuf = "test2";
printf_s("%s\n", mybuf);

const char *bptr = mybuf; // Pointer to constant data
printf_s("%s\n", bptr);

// *bptr = 'a'; // Error
}

不能声明具有 const 关键字的构造函数或析构函数。

限定成员函数时:

声明带有 const 关键字的成员函数指定,函数是 "只读"函数,在它被调用的时候不会修改对象。 一个常数成员函数不能修改任何非静态数据成员或调用不是常数的任何成员函数。若要声明常数成员函数,请在参数列表的右括号后放置const关键字,把const关键字放在函数的参数表和函数体之间。有人可能会问:为什么不将const放在函数声明前呢?因为这样做意味着函数的返回值是常量,意义完全不同。 声明和定义中均要求该 const 关键字。

// constant_member_function.cpp
class Date
{
public:
Date( int mn, int dy, int yr );
int getMonth() const; // A read-only function
void setMonth( int mn ); // A write function; can't be const
private:
int month;
};

int Date::getMonth() const
{
return month; // Doesn't modify anything
}
void Date::setMonth( int mn )
{
month = mn; // Modifies data member
}
int main()
{
Date MyDate( 7, 4, 1998 );
const Date BirthDate( 1, 18, 1953 );
MyDate.setMonth( 4 ); // Okay
BirthDate.getMonth(); // Okay
BirthDate.setMonth( 4 ); // C2662 Error
}

限定函数的传递值参数:

void function(const int Var); //传递过来的参数在函数内不可以改变.

限定函数返回值型.

const int function(); //此时const无意义

const myclassname function(); //函数返回自定义类型myclassname.

限定函数类型.

void function()const; //常成员函数, 常成员函数是不能改变成员变量值的函数。

非常量成员函数不能被常量成员对象调用,因为它可能企图修改常量的数据成员. 任何不修改成员数据的函数都应该声明为const函数,这样有助于提高程序的可读性和可靠性。

void AddElem(const int);

bool Set::Member (const int elem) const;

const Set s;

s.AddElem(10); // 非法: AddElem不是常量成员函数

s.Member(10); // 正确

构造函数和析构函数对这个规则例外,它们从不定义为常量成员,但可被常量对象调用(被自动调用)。它们也能给常量的数据成员赋值,除非数据成员本身是常量。

const成员函数和const对象

实际上,const成员函数还有另外一项作用,即常量对象相关。对于内置的数据类型,我们可以定义它们的常量,用户自定义的类也一样,可以定义它们的常量对象。例如,定义一个整型常量的方法为:

const int i=1 ;

同样,也可以定义常量对象,假定有一个类classA,定义该类的常量对象的方法为:

const classA a(2);

这里,a是类classA的一个const对象,"2"传给它的构造函数参数。const对象的数据成员在对象寿命期内不能改变。但是,如何保证该类的数据成员不被改变呢?

为了确保const对象的数据成员不会被改变,在C++中,const对象只能调用const成员函数。如果一个成员函数实际上没有对数据成员作任何形式的修改,但是它没有被const关键字限定的,也不能被常量对象调用。下面通过一个例子来说明这个问题:

class C

{

int X;

public:

int GetX()

{

return X;

}

void SetX(int X)

{

this->X = X;

}

};

void main()

{

const C constC;

cout<<constC.GetX();

}

如果我们编译上面的程序代码,编译器会出现错误提示:constC是个常量对象,它只能调用const成员函数。虽然GetX( )函数实际上并没有改变数据成员X,由于没有const关键字限定,所以仍旧不能被constC对象调用。如果我们将上述代码中:

int GetX()

改写成:

int GetX()const

再重新编译,就没有问题了。

来自 <http://baike.baidu.com/view/1065598.htm?force=1>

来自 <http://baike.baidu.com/subview/1065598/5048429.htm>

来自 <http://baike.baidu.com/link?url=8jF47vyuKcX_V6Ou641cceF23p3O22ikl5BahPy0oljLe7SIubsQ4B5sPXDUsVRtYXkQfh12pSx9rG3uOsleNMMgZp2bTCJYgtedJcOjnS2JgL87DU3Qw-O-rEK8JlRE>

来自 <http://msdn.microsoft.com/zh-cn/library/vstudio/07x6b05d(v=vs.120).aspx>

来自 <http://msdn.microsoft.com/zh-cn/library/vstudio/357syhfh.aspx>

来自 <http://msdn.microsoft.com/zh-cn/library/vstudio/6ke686zh.aspx>

C++学习之const整理总结的更多相关文章

  1. canvas学习之API整理笔记(二)

    前面我整理过一篇文章canvas学习之API整理笔记(一),从这篇文章我们已经可以基本了解到常用绘图的API.简单的变换和动画.而本篇文章的主要内容包括高级动画.像素操作.性能优化等知识点,讲解每个知 ...

  2. 一份关于Swift语言学习资源的整理文件

    一份关于Swift语言学习资源的整理文件     周银辉 在这里下载 https://github.com/ipader/SwiftGuide

  3. 【资源】C++学习资料 - 逆天整理 - 精华无密版【最新】

    再失效就太无语了,链接都是多份的~~—————————————————基础——————————————C++环境搭建(全套)http://pan.baidu.com/s/1o6y0smY链接:http ...

  4. iOS学习笔记-精华整理

    iOS学习笔记总结整理 一.内存管理情况 1- autorelease,当用户的代码在持续运行时,自动释放池是不会被销毁的,这段时间内用户可以安全地使用自动释放的对象.当用户的代码运行告一段 落,开始 ...

  5. iOS学习笔记总结整理

    来源:http://mobile.51cto.com/iphone-386851_all.htm 学习IOS开发这对于一个初学者来说,是一件非常挠头的事情.其实学习IOS开发无外乎平时的积累与总结.下 ...

  6. 学习ReactNative笔记整理一___JavaScript基础

    学习ReactNative笔记整理一___JavaScript基础 ★★★笔记时间- 2017-1-9 ★★★ 前言: 现在跨平台是一个趋势,这样可以减少开发和维护的成本.第一次看是看的ReactNa ...

  7. (zhuan) 126 篇殿堂级深度学习论文分类整理 从入门到应用

    126 篇殿堂级深度学习论文分类整理 从入门到应用 | 干货 雷锋网 作者: 三川 2017-03-02 18:40:00 查看源网址 阅读数:66 如果你有非常大的决心从事深度学习,又不想在这一行打 ...

  8. NodeJS-001-Nodejs学习文档整理(转-出自http://www.cnblogs.com/xucheng)

    Nodejs学习文档整理 http://www.cnblogs.com/xucheng/p/3988835.html 1.nodejs是什么: nodejs是一个是javascript能在后台运行的平 ...

  9. Python编程:基础学习常见错误整理

    # Python学习之错误整理: # 错误一:# TypeError: cannot concatenate 'str' and 'int' objects# 不能连接str和int对象age = 2 ...

随机推荐

  1. AIX 第4章 指令记录

    root@db:/#lsdev -Cc disk --查看磁盘设备信息   -C customized -c class hdisk0       Available 00-08-00 SAS Dis ...

  2. HDU 3078 Network

    简单的  RMQ:  先预处理得到  所有 节点的 公共祖先  和  dfs 得到所有节点的父亲节点:  然后  询问时,从自己出发向上找父亲, 然后  得到所有的节点:排序一下 不知道  这题这样也 ...

  3. 定时组件quartz系列<三>quartz调度机制调研及源码分析

    quartz2.2.1集群调度机制调研及源码分析引言quartz集群架构调度器实例化调度过程触发器的获取触发trigger:Job执行过程:总结:附: 引言 quratz是目前最为成熟,使用最广泛的j ...

  4. 嵌入式 hi3518平台多路码流添加osd

    <span style="font-family:Courier New;"> /******************************************* ...

  5. Oracle自定义数据类型 2 (调用对象方法)

    调用对象方法 调用对象方法基于类型创建表后,就可以在查询中调用对象方法 A. 创建基于对象的表语法: create   table   <表名>   of   <对象类型>意义 ...

  6. win7 下配置resin的一些tip

    一.如何查看jdk安装目录: 通过不同方法搜索javac看看, javac.exe 是java的编译器: 可用的搜索方法: 1.cmd 控制台:  where javac 2.开始菜单的搜索: 一直到 ...

  7. Drupal 7.23:函数drupal_alter()注释

    /** * Passes alterable variables to specific hook_TYPE_alter() implementations. * * This dispatch fu ...

  8. ajax连接池和XMLHttpRequest

    连接池 我们公司在路由和交换机web界面和后端交互全部采用的是自己封装的ajax组件完成的,组件有点老了,代码风格和其中的某些用法现在看起来都有点不习惯.今天把这个组件的核心部分的ajax连接池记录下 ...

  9. margin四个元素的顺序

    如果margin给的是四个值比如:margin:0px 0px 0px 0px;代表:margin: top right bottom left代表从上右下左,顺时针方向.如果margin给的是三个值 ...

  10. linux grub

    grub 是目前使用最广泛的linux引导装载程序,旧的lilo这个引导装载程序很少见了,grub优点: 支持较多哦的文件系统,可以使用grub主程序在文件系统中查找内核文件名 启动的时候,可以自行编 ...