引用和类型强转

引用

引用的特点

引用 即内存的 别名  

        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; // ok
    const int& cra = a; // ok

    const int b = 10;
//  int& rb = b; // err
    const 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); // 在堆上分配一个整数并初始化为10
    return *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; // 输出10
    ref = 90; // 修改堆上对象的值
    cout << "Modified value: " << ref << endl; // 输出90
    delete &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;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值