这里的T指的是一种数据类型,可以是int、long、doule等基本数据类型,也可以是自己类型的类型class。单独的一个const你肯定知道指的是一个常量,但const与其他类型联合起来的众多变化,你是不是就糊涂了?下面我们一一来解析。

const T

定义一个常量,声明的同时必须进行初始化。一旦声明,这个值将不能被改变。

int i = 5;
const int constInt = 10;        //正确
const int constInt2 = i;        //正确
constInt = 20;                  //错误,常量值不可被改变
const int constInt3;            //错误,未被初始化

const T*

指向常量的指针,不能用于改变其所指向的对象的值。

const int i = 5;
const int i2 = 10;
const int* pInt = &i;           //正确,指向一个const int对象,即i的地址
//*pInt = 10;                   //错误,不能改变其所指缶的对象
pInt = &i2;                     //正确,可以改变pInt指针本身的值,此时pInt指向的是i2的地址
const int* p2 = new int(8);     //正确,指向一个new出来的对象的地址
delete p2;                      //正确
//int* pInt = &i;               //错误,i是const int类型,类型不匹配,不能将const int * 初始化为int *
int nValue = 15;
const int * pConstInt = &nValue;    //正确,可以把int *赋给const int *,但是pConstInt不能改变其所指向对象的值,即nValue
*pConstInt = 40;                    //错误,不能改变其所指向对象的值

const int* 与int* const的区别

指针本身就是一种对象,把指针定义为常量就是常量指针,也就是int* const的类型,也可以写成int *const,声明时必须初始化。

int nValue = 10;
int* const p = &nValue;
int *const p2 = &nValue;
const int* 指针指向的对象不可以改变,但指针本身的值可以改变;int* const 指针本身的值不可改变,但其指向的对象可以改变。
int nValue1 = 10;
int nValue2 = 20;
int* const constPoint = &nValue1;
//constPoint = & nValue2;           //错误,不能改变constPoint本身的值
*constPoint = 40;                   //正确,可以改变constPoint所指向的对象,此时nValue1 = 40const int nConstValue1 = 5;
const int nConstValue2 = 15;
const int* pPoint = &nConstValue1;
//*pPoint  = 55;                    //错误,不能改变pPoint所指向对象的值
pPoint = &nConstValue2;             //正确,可以改变pPoint指针本身的值,此时pPoint邦定的是nConstValue2对象,即pPoint为nConstValue2的地址

const int* const 是一个指向常量对象的常量指针,即不可以改变指针本身的值,也不可以改变指针指向的对象。

const int nConstValue1 = 5;
const int nConstValue2 = 15;
const int* const pPoint = &nConstValue1;
//*pPoint  = 55;                    //错误,不能改变pPoint所指向对象的值
//pPoint = &nConstValue2;           //错误,不能改变pPoint本身的值

const T&

对常量(const)的引用,又称为常量引用,常量引用不能修改其邦定的对象。

int i = 5;
const int constInt = 10;
const int& rConstInt = constInt;    //正确,引用及邦定的值都是常量
rConstInt = 5;                      //错误,不能改变引用所指向的对象

允许为一个常量引用邦定一个非常量对象、字面值,甚至是表达式;引用的类型与引用所指向的类型必须一致。

int i = 5;
int& rInt = i;                      //正确,int的引用
const int constInt = 10;
const int& rConstInt = constInt;    //正确,引用及邦定的值都是常量
const int& rConstInt2 = rInt;       //正确,用rInt邦定的对象进行赋值
rInt = 30;                          //这时,rConstInt2、rInt、i的值都为30
//rConstInt2 = 30;                  //错误,rConstInt2是常量引用,rConstInt2本身不能改变所指向的对象int i2 = 15;
const int& rConstInt3 = i2;         //正确,用非常量的对象为其赋值
const int& rConstInt4 = i + i2;     //正确,用表达式为其赋值,值为45
i = 20;                             //此时i=20, rInt = 20, rConstInt4 = 45,说明rConstInt4邦定的是i + i2的临时变量
const int& rConstInt5 = 50;         //正解,用一个常量值为其赋值

const T*&与T *const&

指向常量对象的指针的引用,这可以分两步来理解:1.const T*是指向常量的指针;2.const T*&指向常量的指针的引用。

const int nConstValue = 1;                      //常量对象
const int nConstValue2 = 2;                     //常量对象
const int* pConstValue = &nConstValue;          //指向常量对象的指针
const int* pConstValue2 = &nConstValue2;        //指向常量对象的指针
const int*& rpConstValue = pConstValue;         //指向常量对象的指针的引用
//*rpConstValue = 10;                           //错误,rpConstValue指向的是常量对象,常量对象的值不可改变
rpConstValue = pConstValue2;                    //正确,此时pConstValue的值等于pConstValue2
//指向常量对象的指针本身是对象,引用可以改变邦定对象的值int nValue = 5;
int nValue2 = 10;
int *const constPoint = &nValue;                //常量指针
int *const constPoint2 = &nValue2;              //常量指针
int *const &rpConstPoint = constPoint;          //对常量指针的引用,邦定constPoint
//rpConstPoint = constPoint2;                   //错误,constPoint是常量指针,指针本身的值不可改变
*rpConstPoint = 20;                             //正确,指针指向的对象可以改变

在函数中的应用

我们直接从需求出来,假设有这样一个数据结构:

typedef struct __Data
{int value;
public:__Data():value(0){}
}Data;

1.希望传入一个对象,又不想让函数体修改这个对象。

方式<1>

void Dealwith(const Data& data)
{cout << data.value << endl;//data.value = 5;       //错误,data是常量引用,不能改变其邦定的对象
}

这种方式还有一个好处是只有在调用函数的时候会邦定对象,传递的是对象的引用,而不是对象,减少函数调用时对象赋值的花销。

方式<2>

void Dealwith(const Data* pData)
{cout << pData->value << endl;//pData->value = 5;     //错误,pData是指向常量对象的指针,不能改变其指向的对象
}

这种方式与void Dealwith(const Data& data)的功能相同

方式<3>

Data g_data(20);
void Dealwith(const Data*& pData)
{cout << pData->value << endl;//pData->value = 5;     //错误,pData邦定的是指向常量对象的指针,常量对象的指针不能改变其指向的对象pData = &g_data;        //正确,pData是[指向常量对象的指针]的引用,引用可改变其邦定的对象
}

调用如下:

Data d(10);
const Data* pData = &d;
Dealwith(pData);
cout << pData->value << endl;   //此时pData->value为20,d.value还是10

这种方式函数未改变传入的对象的值,但可以返回另外一个对象的指针。注意返回的指针必须指向全局的对象,如果返回函数内定义的对象,退出函数作用域后,其指针将无效,这是非常危险的;如果Dealwith是成员函数,也可以返回指向成员的指针。

2.在类中的使用,返回一个类的成员,但不希望调用方修改这个成员。

方式<1>

class MyData
{
public :MyData(std::string name, Data data){m_name = name;m_data = data;}const Data* GetData(){return &m_data;}private:std::string m_name;Data m_data;
};

调用如下:

MyData mydata("", Data(100));
const Data* pData = mydata.GetData();
cout << pData->value << endl;   //pData->value = 100
//pData->value = 50;            //错误,pData是指向常量对象的指向,不能改变其指向对象的值 

方式<2>

有人可能会问GetData也可以写成这样:

const Data& GetData()
{return m_data;
}

这样的话,调用方常常容易写成这样:

MyData mydata("", Data(100));
Data data = mydata.GetData();   //这会有个赋值的过程,会把mydata.m_data赋给data
cout << data.value << endl;     //data.value = 100
data.value = 50;                //正确,data.value=50,但mydata.m_data.value还是100

这样调用时会有一个结果赋值的过程,如果Data是一个复杂的类,会有较大的开销,其效果与下面这种方式是一样的:

Data GetData()
{return m_data;
}

当然,如果调用方这样使用是正确的:

const Data& GetData()
{return m_data;
}
MyData mydata("", Data(100));
const Data& data = mydata.GetData();    //这会有个赋值的过程,会把mydata.m_data赋给data
cout << data.value << endl;             //data.value = 100
//data.value = 50;                      //错误,data是一个对常量的引用,不能改变其邦定的对象

这对调用方的技术能力要求比较高,如果你是设计方,一定要尽量使接口简单易用。

方式<3>

如果你要传入一个Data进行一些处理,处理完后返回类的成员m_data,可如下实现:

void DoSomething(const Data*& pData)
{if (pData != NULL){// doto: 这里实现你要处理的功能}pData = &m_data;
}

如果您有什么疑惑和想法,请在评论处给予反馈,您的反馈就是最好的测评师!由于本人技术和能力有限,如果本博文有错误或不足之处,敬请谅解并给出您宝贵的建议!


如果您有什么疑惑和想法,请在评论处给予反馈,您的反馈就是最好的测评师!由于本人技术和能力有限,如果本博文有错误或不足之处,敬请谅解并给出您宝贵的建议!



const T、const T*、T *const、const T、const T* 的区别相关推荐

  1. 容器的访问元素的成员函数(front,back,下标和at)返回的都是引用,如果顺序容器是const的对象,那么返回的是const的引用

    顺序容器的访问元素的成员函数(front,back,下标和at)返回的都是引用,如果顺序容器是const的对象,那么返回的是const的引用,下面有个例子说明问题: #include <iost ...

  2. const 常量_条款03:尽可能使用const

    const 允许你指定一个语义约束(也就是指定一个"不该被改动"的对象),而编译器会强制实施这项约束. 1.const指针 如果关键字const出现在星号左边,表示被指物是常量:如 ...

  3. const 常量_软件特攻队|const常量,不一样的新玩法

    const用于申明变量,放于变量类型之前,表示此变量不可被改变.然而C语言和C++中的const有着不一样的意义.如下所示: const int a = 10; int *p = &a; 上面 ...

  4. const 作用 c语言,在C语言中const 作用的的全面总结.doc

    右面拒账则川盾衡徊洁豁却尤骂登硫矢窍松寝春摘慌瘪悯嚏蓑篓雍淫东佳粮瘤遍榜柔脾右晕沮椒肃蛾闲惹戚谩智胜汁秀玉怠继纺侥圃唯需齿翟顿稽吩餐音欧宪撅虐镁级脖铲贵酋挚昂藕瓢需冷乃依萎听滚俄郭奴痈急欲沾挂畅好姐载 ...

  5. c语言 const常量_C编程中的常量(const)

    c语言 const常量 const is a keyword in C language, it is also known as type qualifier (which is to change ...

  6. C++中的const成员函数(函数声明后加const,或称常量成员函数)用法详解

  7. 【C语言趣味教程】(5) 常量:字面常量 | 类型常量 | const 关键字 | const 的声明 | 程序中的只读概念 | const 保护机制 | 如何巧妙区分 “指针常量“ 和 “常量指针“

  8. 【C++自我精讲】基础系列二 const

    [C++自我精讲]基础系列二 const 0 前言 分三部分:const用法.const和#define比较.const作用. 1 const用法 const常量:const可以用来定义常量,不可改变 ...

  9. C++:const的使用(普通常量、指针、引用)

    const声明的是常量,常量基本上只能读不能写.其实x也是能写的,但他只是在x初始化的时候完成了写操作. int main() {const int x=4;//x是const int型.在初始化时写 ...

  10. the different between Const and Static in C++

    1.const规定了一个变量在它初始化值之后,值不能再改变,也就是只读. 来看个例子: const测试例子 在这个测试程序里,我试图在初始化变量c的值之后再修改c的值,编译直接报错,告诉我c已经是一个 ...

最新文章

  1. 很安逸的离线API文档查询工具Dash和Zeal
  2. hadoop端口号列表
  3. jexcel可以合并单元格么_含金量超高的3个文本、字符合并实用技巧解读!
  4. linux 安装nginx php mysql 配置文件在哪_linux下 php+nginx+mysql安装配置
  5. python魔法方法str_8.9.魔法方法 - str()方法
  6. JavaScript学习(五十五)—组合继承
  7. Citrix为什么要兼容第三方服务器虚拟化平台
  8. 视频教程-通俗易懂的JavaScript高级教程(含资料)-JavaScript
  9. Matlab中值滤波去噪
  10. excel wps安装access2010数据库引擎
  11. android 闹钟设置的几种方法
  12. Apache网页与安全优化之--网页压缩
  13. 史上最详细的梯度下降优化算法介绍(从SGD到Adam至Lookahead)
  14. Spring5.0响应式编程入门
  15. [wireshark] 码率统计
  16. Altium Designer快捷键
  17. 字符串查找函数和错误信息报告函数
  18. linux软raid阅读笔记,linux_软RAID阅读笔记.pdf
  19. docker容器日常管理(四)
  20. java华为_华为 Java

热门文章

  1. render方法的使用
  2. centos tcpdump
  3. netty的epoll和linux的epoll是如何实现的
  4. TM1650芯片驱动四位数码管
  5. 学习笔记—增量式PID详细实现(C语言)
  6. 目标检测的Tricks | 【Trick5】学习率调优方法——warmup
  7. MATLAB plot3绘制的不是三维图
  8. 网络和网路互联的设计
  9. WebRTC实时通信系列教程8 打通P2P连接和信令通信
  10. IDEA类和方法注释模板设置