C++关于const与引用的分析讲解

目录
  • 一、关于 const 的疑问
  • 二、关于引用的疑问
  • 三、小结

一、关于 const 的疑问

const 什么时候为只读变量?什么时候是常量?

const 常量的判别准则

  • 只有用字面量初始化的 const 常量才会进入符号表
  • 使用其他变量初始化的 const 常量仍然是只读变量
  • 被 volatile 修饰的 const 常量不会进入符号表

注:在编译期间不能直接确定初始值的 const 标识符,都被作为只读变量处理。

const 引用的类型与初始化变量的类型 如果相同,则初始化变量成为只读变量;如果不同 ,则生成一个新的只读变量。

下面看一段 const 典型问题分析的代码:

#include <stdio.h>

int main()
{
    const int x = 1;
    const int& rx = x;
    int& nrx = const_cast<int&>(rx);
    nrx = 5;
    printf("x = %d\n", x);
    printf("rx = %d\n", rx);
    printf("nrx = %d\n", nrx);
    printf("&x = %p\n", &x);
    printf("&rx = %p\n", &rx);
    printf("&nrx = %p\n", &nrx);
    volatile const int y = 2;
    int* p = const_cast<int*>(&y);
    *p = 6;
    printf("y = %d\n", y);
    printf("p = %p\n", p);
    const int z = y;
    p = const_cast<int*>(&z);
    *p = 7;
    printf("z = %d\n", z);
    printf("p = %p\n", p);
    char c = 'c';
    char& rc = c;
    const int& trc = c;
    rc = 'a';
    printf("c = %c\n", c);
    printf("rc = %c\n", rc);
    printf("trc = %c\n", trc);
    return 0;
}

下面为输出结果:

第一个需要注意的地方就是 使用字面量初始化的 const 常量才会进入符号表,所以打印出的x的值为1,而不是5。rx 代表的是 C++ 编译器为 x 常量分配但是没有使用的空间,为只读变量。const_cast 消除了只读变量的只读属性,所以得到的 nrx 为一个普通变量,且 nrx 也代表一个内存空间,这段内存空间与 rx 代表的内存空间为同一段。所以运行后 x,rx以及 nrx 所代表的的地址都是一样。

第二个需要注意的地方就是被 volatile 修饰的 const 常量不会进入符号表,所以修饰的常量为只读变量。const_cast 消除了 y 地址的只读属性,所以可以用一个普通指针 p 指向 y 的地址,所以改变 p 指针里面的内容,y 的值也会改变。

第三个需要注意的地方就是使用其他变量初始化的 const 常量仍然是只读变量。所以令 const int z = y 后,依然可以使用指针改变 z 的值。

第四个需要注意的地方就是const 引用的类型与初始化变量的类型 如果相同,则初始化变量成为只读变量;如果不同 ,则生成一个新的只读变量。所以 trc 的值和上面的 c 和 rc不一样。

二、关于引用的疑问

引用与指针有什么关系?如何理解“引用的本质就是指针常量”?

指针是一个变量

  • 值为一个内存地址,不需要初始化,可以保存不同的地址
  • 通过指针可以访问对应内存地址中的值
  • 指针可以被 const 修饰成为常量或者只读变量

引用只是一个变量的新名字

  • 对引用的操作(赋值,取地址等)都会传递到代表的变量上
  • const 引用使其代表的变量具有只读属性
  • 引用必须在定义时初始化,之后无法代表其它变量

从使用 C++ 语言的角度来看

  • 引用与指针没有任何的关系
  • 引用是变量的新名字,操作引用就是操作对应的变量

从 C++ 编译器的角度来看

  • 为了支持新概念“引用”必须要一个有效的解决方案
  • 在编译器内部,使用指针常量来实现“引用”
  • 因此“引用”在定义时必须初始化

在工程项目开发中

  • 当进行 C++ 编程时,直接站在使用的角度看待引用,与指针毫无关系,引用就是变量的别名
  • 当对 C++ 代码进行调试分析时,一些特殊情况,可以考虑站在C++编译器的角度看待引用

下面看一段引用典型问题分析:

#include <stdio.h>

int a = 1;
struct SV
{
    int& x;
    int& y;
    int& z;
};
int main()
{
    int b = 2;
    int* pc = new int(3);
    SV sv = {a, b, *pc};
    //int& array[] = {a, b, *pc}; // &array[1] - &array[0] = ?  Expected ==> 4
    printf("&sv.x = %p\n", &sv.x);
    printf("&sv.y = %p\n", &sv.y);
    printf("&sv.z = %p\n", &sv.z);
    delete pc;
    return 0;
}

下面为输出结果:

在C语言和 C++ 中数组的地址都是递增的,而在该代码中可以看到第1个元素的地址减去第二个元素的地址不为4,所以说明C++中不支持引用数组。

三、小结

  • 指针是一个变量
  • 引用是一个变量的新名字
  • const 引用能够生成新的只读变量
  • 在编译器内部使用指针常量实现“引用”
  • 编译时不能直接确定初始值的 const 标识符都是只读变量

到此这篇关于C++关于const与引用的分析讲解的文章就介绍到这了,更多相关C++const与引用内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++引用的使用与const修饰符

    目录 1.引用 2.函数引用传递 3.引用与const 4.const修饰符的优点 1.引用 引用是给已经定义的变量一个别名,可以简单理解成同一个变量的昵称.既然是昵称或者是别名,显然它和原本的变量名有着同样的效力.所以我们对别名进行修改,原本的变量值也一样会发生变化. 我们通过符号&来表明引用, 比如下面这个例子,我们创建了a变量的一个引用b int a = 3; int &b = a; b++; cout << a << endl; 由于b是a的一个引用,本质上

  • c++ const引用与非const引用介绍

    const引用是指向const对象的引用. 复制代码 代码如下: const int i = 10; const int &ref = i; 可以读取ref,但不能修改.这样做是有意义的,因为i本身就不可修改,当然也不能通过ref来修改了.所以也就有将const变量赋值给非const引用是非法的. 复制代码 代码如下: int &ref1 = i; // error: nonconst reference to a const object 非const引用是指向非const类型变量的引用

  • C++中引用和const关键字介绍

    目录 引用 常引用 const关键字用法 1)定义常量 2)定义常量指针 3)定义常引用 总结 引用 下面的写法定义了一个引用,并将其初始化为引用某个变量.类型名 & 引用名 = 某变量名; int n = 4; int & r = n; // r 引用了n,r的类型是 int & 某个变量的引用,等价于这个变量,相当于该变量的一个别名. int n = 7; int & r = n; // r 引用了n,r和n就是一回事 r = 4; cout << r; /

  • 浅析C++的引用与const指针与各种传递方式

    浅析C++的引用与const指针与各种传递方式 首先我们知道 const int *p 与 int const *p 是一样的,即 *p 是常量:而 int * const p 跟上面是不一样的,即 p 是常量:我们知道引用只是一个别名,与变量共享存储空间,并且必须在定义的时候初始化,而且不能再成为别的变量的别名,这让我们想到什么呢,貌似跟  int * const p   的性质很像. 其实引用的底层就是用const指针来实现的.下面举个小例子: #include <iostream> us

  • c++中临时变量不能作为非const的引用参数的方法

    试看下面的代码: #include <iostream> using namespace std; void f(int &a) { cout << "f(" << a << ") is being called" << endl; } void g(const int &a) { cout << "g(" << a << "

  • C++ const引用、临时变量 引用参数详解

    C++引用-临时变量.引用参数和const引用 如果实参与引用参数不匹配,C++将生成临时变量.如果引用参数是const,则编译器在下面两种情况下生成临时变量: 实参类型是正确的,但不是左值 实参类型不正确,但可以转换为正确的类型 左值参数是可被引用的数据对象,例如,变量.数组元素.结构成员.引用和被解除引用的指针都是左值,非左值包括字面常量和包含多项式的表达式.定义一个函数 Double refcube(const double& ra) { Returnra*ra*ra; } double

  • C++关于const与引用的分析讲解

    目录 一.关于 const 的疑问 二.关于引用的疑问 三.小结 一.关于 const 的疑问 const 什么时候为只读变量?什么时候是常量? const 常量的判别准则 只有用字面量初始化的 const 常量才会进入符号表 使用其他变量初始化的 const 常量仍然是只读变量 被 volatile 修饰的 const 常量不会进入符号表 注:在编译期间不能直接确定初始值的 const 标识符,都被作为只读变量处理. const 引用的类型与初始化变量的类型 如果相同,则初始化变量成为只读变量

  • C++详细分析讲解引用的概念与使用

    目录 1.引用的概念 2.引用的格式 3.引用的特性 4.取别名原则 5.引用的使用场景 做参数 做返回值 int&Count()的讲解 传值传引用效率比较 6.引用和指针的不同点 1.引用的概念 引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间. 2.引用的格式 类型 & 引用变量名 ( 对象名 ) = 引用实体: 举例如下: 注意:引用类型必须和引用实体是同种类型的 3.引用的特性 (1). 引用在 定义时必须初

  • C++简明分析讲解引用与函数提高及重载

    目录 详解引用 引用的基本使用 引用做函数参数 引用做函数返回值 常量引用 引用的本质 函数提高 函数默认值 函数占位参数 函数重载及注意事项 详解引用 引用的基本使用 语法:数据类型 &新变量名 =原来变量名 作用:给变量起别名 注意事项: 1.引用必须初始化 2.一旦初始化就不能更改(具体原因在下面引用本质上会讲到) 示例: int a = 10; int c = 20; 如果写 int &b;这是错误的,没有初始化引用,编译器不知道b指向的地址. 所以这样写 int &b=a

  • C++简明分析讲解布尔类型及引用

    目录 一.C++中的布尔类型 二.C++中的三目运算符 三.C++中的引用 四.总结 一.C++中的布尔类型 C++在C语言的基本类型系统之上增加了bool C++中的bool可取的值只有true和 false 理论上bool只占用一个字节 C++编译器会将非0值转换为true ,0值转换为false 注意: true代表真值,编译器内部用1来表示 false代表非真值,编译器内部用0来表示 下面看一下这段代码,加深一下对bool类型的理解. #include <stdio.h> int ma

  • C语言详细分析讲解关键字const与volatile的用法

    目录 一.const 只读变量 二.const 全局变量的分歧 三.const 的本质 四.const 修饰函数参数和返回值 五.volatile 解析 六.小结 一.const 只读变量 const 修饰的变量是只读的,本质还是变量 const 修饰的局部变量在栈上分配空间 const 修饰的全局变量在全局数据区分配空间 const 只在编译期有用,在运行期无用 const 修饰的变量不是真的常量,它只是告诉编译器该变量不能出现在赋值符号的左边. 二.const 全局变量的分歧 在现代C语言编

  • JavaScript错误处理机制全面分析讲解

    目录 1. Error 实例 2. 原生错误类型 2.1 ReferenceError 2.2 SyntaxError 2.3 TypeError 2.4 RangeError 2.5 URIError 2.6 evalError 3. 自定义错误类型 4. throw 5. try…catch 6. finally 总结 1. Error 实例 JavaScript在运行错误时会抛出一个错误,JS提供了Error构造函数,所有抛出的错误都是这个构造函数的实例 const err = new E

  • JavaScript自动内存管理与垃圾回收策略详细分析讲解

    目录 自动内存管理 垃圾回收策略 标记清理策略 引用计数策略 内存管理技巧 解除引用 const和let变量声明 自动内存管理 JavaScript编程语言通过自动内存管理实现内存分配和闲置资源回收. 简单来讲就是:只要确定某个变量X不会再被使用了,就将变量X占用的内存进行释放.这种判断是周期性执行的,即:垃圾回收程序隔一定时间就会自动执行一次,以释放某些不必要的内存开支. JavaScript垃圾回收过程中的难点在于:如何正确判定一块内存是否还有用? 垃圾回收策略 在C/C++程序中,我们记忆

  • C++浅拷贝与深拷贝及引用计数分析

    C++浅拷贝与深拷贝及引用计数分析 在C++开发中,经常遇到的一个问题就是与指针相关的内存管理问题,稍有不慎,就会造成内存泄露.内存破坏等严重的问题.不像Java一样,没有指针这个概念,所以也就不必担心与指针相关的一系列问题,但C++不同,从C语言沿袭下来的指针是其一大特点,我们常常要使用new/delete来动态管理内存,那么问题来了,特别是伴随着C++的继承机制,如野指针.无效指针使用.内存泄露.double free.堆碎片等等,这些问题就像地雷一样,一不小心就会踩那么几颗. 先来谈一下C

  • C语言动态规划多种背包问题分析讲解

    目录 写在前面 01背包问题 完全背包问题 多重背包问题 I 多重背包问题 II 为什么可以这样优化呢 一 .二进制与十进制 二 .动态规划的时间复杂度估算 三 .多重背包 分组背包问题 写在前面 之前讲过简单DP,经典01背包问题,在这我将会把背包问题更深入的讲解,希望能帮助大家更好的理解. 01背包问题 C语言数学问题与简单DP01背包问题详解 先回忆一下这个图 在这我再将01背包问题代码发一遍,可以用来做对比. 二维: #include<bits/stdc++.h> using name

  • C++分析讲解类的静态成员函数如何使用

    目录 一.未完成的需求 二.问题分析 三.静态成员函数 四.小结 一.未完成的需求 统计在程序运行期间某个类的对象数目 保证程序的安全性(不能使用全局变量) 随时可以获取当前对象的数目 在[C++基础入门]20.C++中类的静态成员变量中每次打印对象的个数时,都需要依赖于一个对象名,下面看一个代码: #include <stdio.h> class Test { public: static int cCount; public: Test() { cCount++; } ~Test() {

随机推荐