引用和类型强转

2024-09-01 03:20
文章标签 类型 引用 强转

本文主要是介绍引用和类型强转,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

引用

引用的特点

引用 即内存的 别名  

        int a = 10;
        int& b = a;

引用本身 不占内存,并非实体, 引用 的所有操作都是在对 目标内存 进行操
引用必须初始化,且不能更换 目标
---> int c = 20;
--->b = c;//
仅仅是在对引用的 目标内存 进行赋值
不存在引用的引用  
int a = 10;
int & b = a;
int & d = b; //这仅仅是在给a取别名为b和d
引用的常属性须和目标的常属性“ 一致
const int e = 10;

  int& f = e;//ERROR

  const int& g = e;//OK

可以限定更加严格
int a = 10;

  const int& h = a;//OK

 代码演示

//引用
#include<iostream>
using namespace std;
int main(){int a = 10;int& b = a;//不要理解为利用a的数据给b赋值,而是理解为b是a所代表内存的别名b = 20;//表面上是给b赋值,实际上是对a所代表内存的赋值cout << "a = " << a << endl;cout << "b = " << b << endl;//表面上是输出b的值,实际上读取的是a所代表内存的值cout << "&a:" << &a << endl;cout << "&b:" << &b << endl;//a和b指向同一块内存int c = 30;b = c;cout << "a = " << a << endl;cout << "&a:" << &a << ' ' << "&b:" << &b << ' ' << "&c:" << &c << endl;int& d = b;//b是a的别名,所以d也是a的别名(不要理解为引用的引用!!!)cout << "&a:" << &a << ' ' << "&b:" << &b << ' ' << "&d:" << &d << endl;const int e = 40;//int& f = e;//error,去引用时,可以对原类型限定更严格,但不能宽松const int& g = e;//可以给const int取常量引用const int& h = a;//别名可以比真名限定更严格return 0;
}

 引用的作用

引用可以延长 右值 生命周期
常引用  即  万能引用
引用的 生命周期 不能长于 目标

代码演示

// 左值/右值 和 引用
#include <iostream>
using namespace std;
int foo() {int m=10;return m;
}
int main( void ) {
// 当前作用域的生命期
// 具名内存-->能够取址-->左值|非常左值(无const修饰)
//                           |常左值  (有const修饰)int a = 10;int& ra = a; // okconst int& cra = a; // okconst int b = 10;
//  int& rb = b; // errconst int& crb = b; // ok// 语句级的生命期(引用可以延长右值的生命期)
// 匿名内存-->不能取址-->右值|98/03标准给出的结论:更改右值毫无意义
//                           |const int& ri = 10; // 取别名后数据10的生命周期延长为当前别名的生命周期 const int& rf = /*|10|*/ foo(); // (1)分配一块匿名内存 (2)生成跳转指令return 0;
}

 引用的应用

引用型参数

引用型参数,函数的形参是实参的别名,避免对象复制的开销

非常 引用型参数
在函数中 修改 实参值          
引用型参数
防止 对实参的 意外 修改        
接受 常量型 实参

 代码演示

//引用作为函数的形参
#include <iostream>
using namespace std;
void swap(int& x,int& y){ //非常引用型参数:函数内部可以修改实参int temp = x;x = y;y = temp;cout << "x = " << x << " y = " << y <<endl;
}
void swap(int* x,int* y){int temp = *x;*x = *y;*y = temp;cout << "x = " << *x << " y = " << *y << endl;
}
void Print(const int& x,const int& y){ //常引用型参数//x = 10;cout << "x = " << x << " y = " << y << endl;
}int main(){int a = 10;int b = 20;//swap(&a, &b);swap(a, b);Print(a, b);Print(10, 30);return 0;
}

引用型返回值

引用型的返回,从函数中返回引用,一定要保证在函数返回以后,该引用的目标依然有效
可以返回 全局 静态 变量的引用
可以返回在 动态创建 的对象的引用
可以返回 引用型 参数 本身
不能返回 局部 变量 的引用
非常 引用型返回值
通过引用可以修改目标
引用型返回值

                  通过引用不能修改目标

 代码演示

//引用型返回值
#include <iostream>
using namespace std;
int g_value = 10;
int& func(){//返回全局变量的引用    //非常引用型返回值,通过引用可以修改目标return g_value;
}
const int& fun(){//常引用型返回值,通过这个引用不可以修改目标return g_value;
}
int& func2(){//返回静态变量的引用static int s_value = 10;//程序启动就执行,而且只执行一次cout << "s_value = " << s_value << endl;return s_value;
}
int& hum() {int *pn = new int(10); // 在堆上分配一个整数并初始化为10return *pn; // 返回该整数的引用
}
int& pfunc(int& x){return x;//返回引用型参数本身
}
int& boo(){int m = 10;return m; // 返回局部变量的引用(这是错误的,函数结束时m被销毁)!!!
}
int main(){func() = 20;cout << g_value << endl;func2() = 100;func2(); //输出100//返回堆中创建对象的引用int& ref = hum(); // 获取堆上对象的引用cout << "Initial value: " << ref << endl; // 输出10ref = 90; // 修改堆上对象的值cout << "Modified value: " << ref << endl; // 输出90delete &ref; // 手动释放堆上分配的内存//返回引用型参数的引用int v_tomato = 999;pfunc(v_tomato) = 888;cout << "v_tomato = " << v_tomato << endl;return 0;
}

引用与指针的比较

在实现层面,引用就是指针,但在 C++ 语言层面,引用不是 实体 类型,因此 C++ 语言层面引用与指针存在明显的差别
1. 指针可以 不初始化 而引用 必须 初始化。
2. 指针的目标可在初始化后 随意变更 ( 除非是指针常量 ) ,而引用一旦初始化就 无法变更 其目标
3. 存在空指针,不存在 空引用
4. 存在指向指针 指针, 存在 引用 引用
5. 存在指针 的引用 存在 引用 指针
6. 存在指针 数组 ,不存在 引用 数组 ,但存在 数组 引用

 代码演示

//引用 和 指针 的差别
#include <iostream>
using namespace std;int main( void ) {int a=10, b=20;int* p = &a; // 指针可以不做初始化,也可做初始化p = &b; // 指针的目标内存可以随意变更int& r = a; // 引用必须初始化r = b; // 这句代码不会变更 r 所引用的目标内存int** ppa = &p; // 存在二级指针
//  int&& rra = r; // 不存在二级引用int*& rpa = p; // 存在指针的引用
//  int&* pra = &r; // 不存在引用的指针int x,y,z;int* arr[3] = {&x,&y,&z}; // 存在指针的数组
//  int& rra[3] = {x,y,z}; // 不存在引用的数组int m[3];int(&q)[3] = m;// 存在数组的引用return 0;
}

类型强转

显示类型转换

C 风格的显式类型转换
( 目标类型 ) 源类型变量
C++ 风格的显式类型转换
目标类型 ( 源类型变量 )
静态类型转换
static_cast < 目标类型 > ( 源类型变量 )
式类型转换的逆转换
常类型转换
const_cast < 目标类型 > ( 源类型变量 )
去除指针或引用上的 const 属性
解释类型转换
reinterpret_cast < 目标类型 > ( 源类型变量 )
任意类型的指针之间的转换或引用之间的转换
任意类型的指针和整型之间的转换

代码演示

// 显式类型转换(强转)
#include <iostream>
using namespace std;int main( void ) {int a;  double b;   float c;    short d;    char e;// 任何基本类型的变量之间都可以隐式转换a = b = c = d = e;e = d = c = b = a;// 任何其他类型的指针 到 void* 都可以隐式转换void* pv = &a; // int*-->void*pv = &b;pv = &c;pv = &d;pv = &e;// void* 到 任何其他类型的指针 都必须强转***************int* pa = static_cast<int*>(pv); // void*-->int*的反向int*-->void*可以隐式double* pb = static_cast<double*>(pv);float* pc = static_cast<float*>(pv);short* pd = static_cast<short*>(pv);char* pe = static_cast<char*>(pv);// 任何类型非常指针 到 同类型常指针 都可以隐式转换const int* cpa = pa; // int*-->const int*const double* cpb = pb;const float* cpc = pc;const short* cpd = pd;const char* cpe = pe;// 任何类型常指针 到 同类型非常指针 都必须强转**************pa = const_cast<int*>(cpa); pb = const_cast<double*>(cpb);pc = const_cast<float*>(cpc);pd = const_cast<short*>(cpd);pe = const_cast<char*>(cpe);// 除了void*外,其他类型指针之间 都必须强转*******************pb = reinterpret_cast<double*>(pa); pb = reinterpret_cast<double*>(1000);return 0;
}

这篇关于引用和类型强转的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1125801

相关文章

Redis的Zset类型及相关命令详细讲解

《Redis的Zset类型及相关命令详细讲解》:本文主要介绍Redis的Zset类型及相关命令的相关资料,有序集合Zset是一种Redis数据结构,它类似于集合Set,但每个元素都有一个关联的分数... 目录Zset简介ZADDZCARDZCOUNTZRANGEZREVRANGEZRANGEBYSCOREZ

SpringBoot项目中Maven剔除无用Jar引用的最佳实践

《SpringBoot项目中Maven剔除无用Jar引用的最佳实践》在SpringBoot项目开发中,Maven是最常用的构建工具之一,通过Maven,我们可以轻松地管理项目所需的依赖,而,... 目录1、引言2、Maven 依赖管理的基础概念2.1 什么是 Maven 依赖2.2 Maven 的依赖传递机

IDEA如何将String类型转json格式

《IDEA如何将String类型转json格式》在Java中,字符串字面量中的转义字符会被自动转换,但通过网络获取的字符串可能不会自动转换,为了解决IDEA无法识别JSON字符串的问题,可以在本地对字... 目录问题描述问题原因解决方案总结问题描述最近做项目需要使用Ai生成json,可生成String类型

Mysql 中的多表连接和连接类型详解

《Mysql中的多表连接和连接类型详解》这篇文章详细介绍了MySQL中的多表连接及其各种类型,包括内连接、左连接、右连接、全外连接、自连接和交叉连接,通过这些连接方式,可以将分散在不同表中的相关数据... 目录什么是多表连接?1. 内连接(INNER JOIN)2. 左连接(LEFT JOIN 或 LEFT

Redis的Hash类型及相关命令小结

《Redis的Hash类型及相关命令小结》edisHash是一种数据结构,用于存储字段和值的映射关系,本文就来介绍一下Redis的Hash类型及相关命令小结,具有一定的参考价值,感兴趣的可以了解一下... 目录HSETHGETHEXISTSHDELHKEYSHVALSHGETALLHMGETHLENHSET

Python中异常类型ValueError使用方法与场景

《Python中异常类型ValueError使用方法与场景》:本文主要介绍Python中的ValueError异常类型,它在处理不合适的值时抛出,并提供如何有效使用ValueError的建议,文中... 目录前言什么是 ValueError?什么时候会用到 ValueError?场景 1: 转换数据类型场景

C# dynamic类型使用详解

《C#dynamic类型使用详解》C#中的dynamic类型允许在运行时确定对象的类型和成员,跳过编译时类型检查,适用于处理未知类型的对象或与动态语言互操作,dynamic支持动态成员解析、添加和删... 目录简介dynamic 的定义dynamic 的使用动态类型赋值访问成员动态方法调用dynamic 的

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

自定义类型:结构体(续)

目录 一. 结构体的内存对齐 1.1 为什么存在内存对齐? 1.2 修改默认对齐数 二. 结构体传参 三. 结构体实现位段 一. 结构体的内存对齐 在前面的文章里我们已经讲过一部分的内存对齐的知识,并举出了两个例子,我们再举出两个例子继续说明: struct S3{double a;int b;char c;};int mian(){printf("%zd\n",s

【编程底层思考】垃圾收集机制,GC算法,垃圾收集器类型概述

Java的垃圾收集(Garbage Collection,GC)机制是Java语言的一大特色,它负责自动管理内存的回收,释放不再使用的对象所占用的内存。以下是对Java垃圾收集机制的详细介绍: 一、垃圾收集机制概述: 对象存活判断:垃圾收集器定期检查堆内存中的对象,判断哪些对象是“垃圾”,即不再被任何引用链直接或间接引用的对象。内存回收:将判断为垃圾的对象占用的内存进行回收,以便重新使用。