复合类型与const关键字

    前面我们讲了指针和引用的基本用法(指针用法)(引用用法)  , 现在我们来看比较复杂的类型 -- 指针引用。(不存在引用指针)

    这是复合类型 , 指针引用 , 顾名思义 , 指针引用就是对指针的引用。

int i = 0 , *pi = &i;
int *&rpi = pi;    //这里的指针引用应该这样阅读  (int *(&rpi)) , 即是rpi是引用 , 是对整形指针的引用


    C++关键字中的const指的是英文中的constant , 即常量的意思 (下面的常量指const修饰的对象), 所以const 是用来修饰常量的关键字 , 下面来看看const是怎么作用于内置变量的:

const int ci = 0;    //const放在类名前面 , 用0初始化ci
const int ci2 = ci;    //用ci来初始化ci2
//ci++;           错误 , 常量不能改变
//const int ci3;    错误 , 常量必须初始化
    常量除了不能改变自身和必须初始化外 , 跟一般变量一样 , 另外 , 常量只在文本内有效。

    对于类的常量对象 , 与基本类型的常量相似 , 不能改变自身且需要初始化(有默认构造函数就可以执行默认初始化) , const对象不能改变成员变量(对象) , 同时不能调用非const成员函数 , 否则编译器会报错。

const string cs = "Hello";
size_t size = cs.size();    //正确 , string::size() 不会改变内置成员 , 所以被声明为const
//该函数声明为 size_type size() const; 起作用的是后面的const
cout << cs[0] << endl;    //正确
//调用的是该函数的const版
//s[0] = 'h';   错误 , 用一个const对象调用一个非const函数


    const与引用组合 , 会变成一种很特别的引用 --- 常量引用 。 我们可以把非常量对象赋给常量引用 , 这样的话就不能通过引用来修改对象的值 , 实际上这只是引用一厢情愿的认为它代表的对象是常量 , 但我们依然可以通过直接修改对象来达到修改的目的。但反过来 , 不能用一个非常量引用来引用常量 , 因为这样就代表可以用引用来改变常量 , 编译器是不允许这样做的。

int i = 0;
const int & ri = i;
//ri = 5;    //错误 , ri是常量
i = 5;    //正确 , 这样i就变成5了 , 当然ri也是5
const int j = 5;
//int & rj = j;    错误 , 不能用非常量引用表示一个常量对象

    对于常量引用 , 还有一个非常令人难以理解的特征 , 就是可以把右值赋给常量引用 :

const int &r = 10;
const int &r1 = r * 5;
const int &r2 = right_int();    //right_int()返回一个局部int
double d = 10.2;
const int &r3 = d;    //r3的值为10

    上述代码全部都是正确并都能通过编译 , 可能有什么人会有疑问 , 为什么能够将没有对象的右值或者临时对象赋给常量引用 。C++允许为一个常量引用赋予一个右值 , 所以编译器会在内存中另外分配一块临时区域来生成对象 , 再把常量引用绑定到这个对象身上 , 而右值就是用来初始化这个临时对象的。

    根据上述的特征 , 我们可以这样定义函数:

void print(const int & i){
    cout << i << endl;
}
print(5);    //合法
int i = 0;
print(i)  ;  //合法 , 把一个非常量赋给常量引用
print(i + 9);    //合法

    接下来我们来看指针与const的结合 , 这里的const 有两种 , 一种是加在类名前面 , 如 const Typename *pt , 这是指指向常量的指针(不一定是常量 , 也是指针一厢情愿这样认为) , 这种指针不能改变指向的对象的内容 ,但可以改变指向的对象 。还有一种是加在类名后面 , 如 Typename* const pt , 这是指常量指针 , 可以改变只想对象的内容 , 但不能改变指向的对象 。

int i = 0 , j = 0;
const int * pi = &i;    //指向常量的指针(在指针层面是常量 , 实际不一定)
int * const pj = &j;    //指针本身是常量
//(*pi)++;        在指针层面指向的是常量 , 不能改变其值      
pi = &j;          //可以改变指向对象
(*pj)++;          //可以改变指向的对象的内容
//pj = &i;         不能改变指向对象

    对于一个常量 , 可以用一个指向常量的指针来指向它 , 却不能用常量指针来指向它 , 因为指向常量的指针不能对该常量进行改动 , 这符合了常量的规则 , 而常量指针是可以改变指向对象的 , 这就违背了常量的规则。

const int i = 1;
const int * pi1 = &i;    //合法 , 不能改变i的值
//int * const pi2 = &i;   错误 , pi2理论上有能力改变i的值
const int * const pi3 = &i;    //合法 , 既不改变对象也不改变指向


    最后讲一下const返回值的函数 , 对于一个有返回值的函数而言 , 如果返回值是右值(即返回类型名无后缀 , 没有&运算符修饰) , 则我们无法将这个函数放在赋值表达式的左边 , 但如果返回值是一个引用 , 因为它是个左值 , 所以可以直接在赋值表达式左边使用函数 , 如果我们不想函数返回值被修改 , 则需要在类名前加上const修饰:

int f1(int &i){  return i;}
int& f2(int &i){ return i;}
const int& f3(int &i) { return i;}
//示例代码:
int i = 5;
//f1(i) = 10;     错误 ,返回值是右值 , 不能放在赋值语句左边
f2(i) = 10;    //正确 , 把i的值改为10
//f(3) = 10;    错误 , 返回值是一个常量引用 , 不能修改它的值 

    总而言之 , 常量的意思就是不希望你修改它 , 但要记住一点 , 常量不全是在编译阶段就已经确定下来的值 , 很多事要到运行阶段才能获得的。而且 , 在我们说常量的时候 , 有可能指字面值常量 , 有可能指const修饰的常量 , 还有可能指常量表达式 。


    

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值