const用法小结

常类型是指使用类型修饰符const说明的类型,常类型的变量或对象的值是不能被更新的。因此,定义或说明常类型时必须进行初始化。

概述

1. const有什么用途?

在 c程序中,const的用法主要有定义常量、修饰函数参数、修饰函数返回值等3个用处。

在c++程序中,它还可以修饰函数的定义体,定义类中某个成员为常态函数,即不改变类中的数据成员。

被const修改的东西都要受到强制保护,可以预防意外的变动,能提高程序的健壮性。

2. const与#define相比有什么不同?

它们都可以用来定义常量,但const比#define有更多优点:

(1) const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换中可能会产生意料不到的错误(边际效应)。

(2) 在c++中使用const常量而不使用宏常量,即const常量完全取代宏常量。

C++中的Const

一,一般常量和对象常量

  1. 一般常量   一般常量是指简单类型的常量。这种常量在定义时,修饰符const可以用在类型说明符前,也可以用在类型说明符后。如:   int const x=2;   或   const int x=2;   定义或说明一个常数组可采用如下格式:   <类型说明符> const <数组名>[<大小>]…   或者   const <类型说明符> <数组名>[<大小>]…   例如:   int const a[5]={1, 2, 3, 4, 5};

  2. 常对象   常对象是指对象常量,定义格式如下:   <类名> const <对象名>   或者   const <类名> <对象名> 定义常对象时,同样要进行初始化,并且该对象不能再被更新,修饰符const可以放在类名后面,也可以放在类名前面。

二,常指针和常引用

  1. 常指针   使用const修饰指针时,由于const的位置不同,而含意不同。如果const位于星号的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;如果const位于星号的右侧,const就是修饰指针本身,即指针本身是常量。(如果const在*的左边,则被指物为常量;在右边,则指针为常量)下面举两个例子,说明它们的区别。   下面定义的一个指向字符串的常量指针:   char * const prt1 = stringprt1;   其中,ptr1是一个常量指针。因此,下面赋值是非法的。   ptr1 = stringprt2;   而下面的赋值是合法的:   *ptr1 = "m";   因为指针ptr1所指向的变量是可以更新的,不可更新的是常量指针ptr1所指的方向(别的字符串)。   下面定义了一个指向字符串常量的指针:   const * ptr2 = stringprt1;   其中,ptr2是一个指向字符串常量的指针。ptr2所指向的字符串不能更新的,而ptr2是可以更新的。因此,   *ptr2 = "x";   是非法的,而:   ptr2 = stringptr2;   是合法的。   所以,在使用const修饰指针时,应该注意const的位置。定义一个指向字符串的指针常量和定义一个指向字符串常量的指针时,const修饰符的位置不同,前者const放在*和指针名之间,后者const放在类型说明符前。

  2. 常引用   使用const修饰符也可以说明引用,被说明的引用为常引用,该引用所引用的对象不能被更新。其定义格式如下:   const <类型说明符> & <引用名>   例如:   const double & v;   在实际应用中,常指针和常引用往往用来作函数的形参,这样的参数称为常参数。

  在c++面向对象的程序设计中,指针和引用使用得较多,其中使用const修饰的常指针和常引用用得更多。使用常参数则表明该函数不会更新某个参数所指向或所引用的对象,这样,在参数传递过程中就不需要执行拷贝初始化构造函数,这将会改善程序的运行效率。

  下面举一例子说明常指针作函数参数的作法。

[cpp] view plaincopyprint?

  1. #include <iostream>
  2. using namespace std;  
  3. const int n = 6;   
  4. void print(const int *p, int n);   
  5. void main() {   
  6. int array[n];           //数组定义必须使用常量
  7. for (int i=0; i<n;i++)  //输入六个数
  8.         cin>>array[i];   
  9.     print(array, n);        //输出六个数
  10. }   
  11. void print(const int *p, int n)   //表示p指向的内容不可修改,p本身可以修改
  12. {   
  13.     cout<<"{"<<*p;   
  14. for (int i=1; i<n;i++)  
  15.         cout<<","<<*(p+i);   
  16.     cout<<"}"<<endl;  
  17. }   

三,常成员函数   使用const关键字进行说明的成员函数,称为常成员函数。只有常成员函数才有资格操作常对象,没有使用const关键字说明的成员函数不能用来操作常对象。常成员函数说明格式如下:   <类型说明符> <函数名> (<参数表>) const;

本质: 成员函数的第一个参数是const this指针,const修饰的成员函数的第一个参数是const T *this。 其中,const是加在函数说明后面的类型修饰符,它是函数类型的一个组成部分,因此,在函数实现部分也要带const关键字。下面举一例子说明常成员函数的特征。

[cpp] view plaincopyprint?

  1. #include <iostream>
  2. using namespace std;  
  3. class r  
  4. {  
  5. public:  
  6.     r(int a, int b):r1(a),r2(b) {}  
  7. void print();  
  8. void print() const;  
  9. private:  
  10. int r1, r2;  
  11. };  
  12. void r::print()  
  13. {  
  14.     cout<<r1<<","<<r2<<endl;  
  15. }  
  16. void r::print() const
  17. {  
  18.     cout<<"const: "<<r1<<","<<r2<<endl;  
  19. }  
  20. void main()  
  21. {  
  22.     r a(5, 4);  
  23.     a.print();  
  24. const r b(20, 52);  
  25.     b.print();  
  26. }  

该例子的输出结果为:  

5,4  20;52  

该程序的类声明了两个成员函数,其类型是不同的(其实就是重载成员函数)。

有带const修饰符的成员函数处理const常量,这也体现出函数重载的特点。

四,常数据成员  

类型修饰符const不仅可以说明成员函数,也可以说明数据成员。

由于const类型对象必须被初始化,并且不能更新,因此,在类中说明了const数据成员时,只能通过成员初始化列表的方式来生成构造函数对数据成员初始化。

下面通过一个例子讲述使用成员初始化列表来生成构造函数。

[cpp] view plaincopyprint?

  1. #include <iostream>
  2. using namespace std;  
  3. class T  
  4. {  
  5. public:  
  6.     T(int i);  
  7. void print();  
  8. const int &r;  
  9. private:  
  10. const int a;  
  11. static const int b=10;//静态常量初始化可以在类内,也可以在类外
  12. };  
  13. //const int T::b=20; //也可以在类外,但是只能初始化一次

[cpp] view plaincopyprint?

  1. T::T(int i):a(i),r(a)          //必须在初始化列表中给常量初始化,但是不能初始化静态常量
  2. {  
  3. //a=i; //这里不可以
  4. }  
  5. void T::print()  
  6. {  
  7.     cout<<r<<":"<<b<<":"<<a<<endl;  
  8. }  
  9. void main()  
  10. {  
  11.     T a1(100), a2(0);  
  12.     a1.print();  
  13.     a2.print();  
  14. }  

  该程序的运行结果为:   100:10:100    0:10:0   在该程序中,说明了如下三个常类型数据成员:   const int & r;   const int a;   static const int b;   其中,r是常int型引用,a是常int型变量,b是静态常int型变量。   程序中对静态数据成员b进行初始化。   值得注意的是构造函数的格式如下所示:   a(int i):a(i),r(a)   {   }   其中,冒号后边是一个数据成员初始化列表,它包含两个初始化项,用逗号进行了分隔,因为数据成员a和r都是常类型的,需要采用初始化格式

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏编程

Python基础知识2:字典

字典一种key - value 的数据类型,就像上学用的字典通过拼音查找汉字一样;字典是Python语言中唯一的映射类型。字典对象是可变的,它是一个容器类型,能...

249100
来自专栏java一日一条

浅谈Java中的equals和==

为什么第3行和第4行的输出结果不一样?==和equals方法之间的区别是什么?如果在初学Java的时候这个问题不弄清楚,就会导致自己在以后编写代码时出现一些低级...

7020
来自专栏黑泽君的专栏

Java中方法重写的两个面试题

  方法重写:     在子类中,出现和父类中一模一样的方法声明的现象。(包含方法名、参数列表和返回值类型都一样)   方法重载:     同一...

33210
来自专栏微信公众号:Java团长

浅谈Java中的equals和==

  为什么第4行和第5行的输出结果不一样?==和equals方法之间的区别是什么?如果在初学Java的时候这个问题不弄清楚,就会导致自己在以后编写代码时出现一些...

9710
来自专栏编程理解

排序算法(二):选择排序

选择排序算法维护一个待排序集合和一个已排序集合,每轮迭代,从待排序集合中选择一个最小(最大)元素,添加到已排序集合中,通过多次迭代,最终完成排序。

11810
来自专栏微信公众号:Java团长

浅谈Java中的equals和==

  为什么第4行和第5行的输出结果不一样?==和equals方法之间的区别是什么?如果在初学Java的时候这个问题不弄清楚,就会导致自己在以后编写代码时出现一些...

10330
来自专栏技术碎碎念

python3 入门 (四) 类与继承

Python 类 Python中的类提供了面向对象编程的所有基本功能:类的继承机制允许多个基类,派生类可以覆盖基类中的任何方法,方法中可以调用基类中的同名方法。...

427120
来自专栏小樱的经验随笔

【Java学习笔记之二十九】Java中的"equals"和"=="的用法及区别

Java中的"equals"和"=="的用法及区别 在初学Java时,可能会经常碰到下面的代码: 1 String str1 = new String("hel...

29970
来自专栏WindCoder

在数组中查找次大值,并与最后一个元素交换—C语言

23810
来自专栏Java 源码分析

静态内部类

定义:静态内部类,定义在类中,任何方法外,用static定义;静态内部类只能访问外部类的静态成员。 注意点: 一般情况下,如果一个内部类不是被定义成静态内部类,...

33780

扫码关注云+社区

领取腾讯云代金券