IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++05引用、显式类型转换 -> 正文阅读

[C++知识库]C++05引用、显式类型转换

前言:更多内容请看总纲《嵌入式C/C++学习路》

1. 引用定义

引用即别名
int a = 10;
int& b = a; // 这里&不是取地址的意思,是引用的意思。 b是一个int型的引用,引用a
int& c = b;

引用必须初始化
int& b; // error!!!
int& b = a;
const int& b = 10;

  • 引用不能为空
  • 引用不能更换目标
#include <iostream>
using namespace std;
int main()
{
    int a = 10;
    int &b = a;
    cout << b << endl;
    ++b; // b 是 a 的别名,对b的操作就是对a的操作
    cout << a << endl;
    int d = 20;
    b = d;   // d 的值赋给b也就是赋给a
    cout << a << endl;
    return 0;
}

在这里插入图片描述

2. 把引用作为参数

引用型参数,函数的形参是实参的别名
——在函数中修改实参值
——避免对象复制的开销

常引用型参数
——接受常量型实参
——防止对实参的意外修改

例子:定义一个函数,交换两个参数a,b的值

#include <iostream>
using namespace std;
// 定义一个函数,交换a,b的值
void swap1(int a, int b)
{
    int c = a;
    a = b;
    b = c;
}

int main(void)
{
    int a = 100, b = 200;
    swap1(a, b);
    cout << a << ' ' << b << endl;
}

在这里插入图片描述
发现这样并不能实现这个功能,因为函数实现的是形参的交换,对实参没有影响。修改如下:

分别通过指针和引用实现:

#include <iostream>
using namespace std;
// 定义一个函数,交换a,b的值
void swap1(int a, int b)
{
    int c = a;
    a = b;
    b = c;
}

void swap2(int *a, int *b)  // 通过指针实现
{
    int c = *a;
    *a = *b;
    *b = c;
}

void swap3(int &a, int &b)  // 通过引用实现
{
    int c = a;
    a = b;
    b = c;
}

int main(void)
{
    int a = 100, b = 200;
    // swap2(&a, &b);
    swap3(a, b);
    cout << a << ' ' << b << endl;
}

在这里插入图片描述

再来看一个例子:交换两个字符串(引用指针)

#include <iostream>
using namespace std;

void swap(const char *x, const char *y) // 此方法不行,交换一级指针的地址应该用二级指针
{
    const char *z = x;
    x = y;
    y = z;
}

void swap2(const char **x, const char **y) // 懵逼了已经  二级指针
{
    const char *z = *x;
    *x = *y;
    *y = z;
}

void swap3(const char *&x, const char *&y)
{
    const char *z = x;
    x = y;
    y = z;
}

int main()
{
    const char *x = "Hello world!";
    const char *y = "Hello C++";
    //   swap(x, y);
    //   swap2(&x, &y);
    swap3(x, y);
    cout << x << ' ' << y << endl;
    return 0;
}

在这里插入图片描述

引用还可以用在结构里:

#include <iostream>
using namespace std;

struct Student
{
    char name[256];
    int age;
};

void print(const Student &s)
{ // const 表示引用目标具有常属性,即不可被修改
    cout << s.name << ' ' << s.age << endl;
    // 每执行一次下面这条语句,age就会加一岁,但是按道理来讲,我们只是为了查看年龄,不应该修改,为了避免这种错误,一般在引用前面加一个const来避免对实参的修改
    // cout << s.name << ' ' << ++s.age << endl;
}

int main(void)
{
    Student s = {"小明", 26};
    print(s);
}

在这里插入图片描述

需要注意的是,实参是常量时,定义函数的形参引用需要加const:

#include <iostream>
using namespace std;

struct Student
{
    char name[256];
    int age;
};

void print(const Student &s)
{ // const 表示引用目标具有常属性,即不可被修改
    cout << s.name << ' ' << s.age << endl;
    // 每执行一次下面这条语句,age就会加一岁,但是按道理来讲,我们只是为了查看年龄,不应该修改,为了避免这种错误,一般在引用前面加一个const来避免对实参的修改
    // cout << s.name << ' ' << ++s.age << endl;
}
void show(const int& i){    // 前面必须加const
    cout << i << endl;
}

int main(void)
{
    Student s = {"小明", 26};
    print(s);
    show(100);  // 100 是常量,形参也需要是const
}

在这里插入图片描述

3.引用型返回值

在C++11中可以取地址的、有名字的就是左值,反之,不能取地址的、没有名字的就是右值

引用型返回值,从函数中返回引用,一定要保证在函数返回以后,该引用的目标依然有效
——返回左值
——可以返回全局、静态乃至成员变量的引用
——可以返回在堆中动态创建的对象的引用
——可以返回调用对象自身的引用
——可以返回引用型参数本身
——不能返回局部变量的引用

常引用型返回值
——返回右值

关于左值右值请参考《C++11 左值、右值、右值引用详解》

来看一个例子(返回左值):

#include <iostream>
using namespace std;

int x;
int &foo(void)  // 返回可修改的左值
{
    return x;
}
int main(void)
{
    foo() = 10; // foo()就是x的别名
    cout << x << endl;
    ++foo();
    cout << x << endl;
    foo() += 10;
    cout << x << endl;
    return 0;
}

在这里插入图片描述

返回成员变量的引用:

#include <iostream>
using namespace std;

struct Student{
    char name[256];
    int age;
    int& howold(void){
        return age;
    }
};

int main(void)
{
    Student s = {"张三",22};
    int x = s.howold();
    cout << x << endl;
    return 0;
}

在这里插入图片描述

返回引用型参数本身:

#include <iostream>
using namespace std;

int& fun(int& r){    // 如果形参写成 int r 就错了,返回的是局部变量的引用
    return r;
}

int main(void)
{
    int y = 100;
    int& r = fun(y);
    ++r;
    cout << y << endl;
    return 0;
}

在这里插入图片描述

常引用型返回值,返回右值

#include <iostream>
using namespace std;
int x = 10;

const int &foo(void)
{
    return x; // 带有常属性,只能做右值
}

int main(void)
{
    cout << foo() << endl;
    //  foo()++; // 错误
    return 0;
}

在这里插入图片描述

4. 引用的本质

在实现层面,引用就是指针,但在语言层面,引用不是实体类型,因此与指针存在明显的差别:

  • 指针可以不初始化,其目标可在初始化后随意变更(除非是指针常量),而引用必须初始化,且一旦初始化就无法变更目标
  • 存在空指针,不存在空引用
  • 存在指向指针的指针,不存在引用引用的引用
  • 存在引用指针的引用,不存在指向引用的指针
  • 存在指针数组,不存在引用数组,但存在数组引用

5. 显式类型转换

定义:显式转换也叫强制转换,是自己主动让这个类型转换成别的类型

  • C风格的显式类型转换-(目标类型)源类型变量
  • C++风格的显式类型转换-目标类型(源类型变量)
  • 静态类型转换
  • ——static_cat<目标类型>(源类型变量)
  • ——隐式类型转换的逆变换
  • ——自定义类型转换
#include <iostream>
using namespace std;

int main(void)
{
    int *pi;
    void *pv = pi; // 任何类型的指针都可以被隐式的转换为void型
    // pi = pv;  // 错误,转换无效,即void*不可以隐式的转换为任何类型的指针,此时可以用static_cat
    pi = static_cast<int *>(pv); // 静态转换
    //  double d = static_cast<double>(pv);  // 错误,double不能被隐式的转换为void*,所以void*也不能静态转换为double类型
    return 0;
}
  • 动态类型转换
  • ——dynamic_cast<目标类型>(源类型变量)
  • ——多态父子类指针或引用之间的转换

后面继承和多态再作介绍

  • 常类型转换
  • ——const_cast<目标类型>(源类型变量)
  • ——去除指针或引用上的const属性
#include <iostream>
using namespace std;

int main(void)
{
    const int *p1; // p1有常属性,p2没有
    //  int * p2 = p1; // 错误:从类型const int*到类型int*的转换无效
    int* p2 = const_cast<int*>(p1);   // 这样就可以,注意:只能去常属性,要是将int转换为char类型就做不到了
    return 0;
}
  • 重解释类型转换
  • ——reinterpret_cast<目标类型>(源类型变量)
  • ——任意类型的指针或引用之间的转换
  • ——任意类型的指针和整型之间的转换
#include <iostream>
using namespace std;

struct Student
{
    char name[256];
    int age;
};

int main(void)
{
    Student s = {"张三",22};
   // char* ps = &s;  // 将struct看成char类型 , 错误!
    char *ps = reinterpret_cast<char*>(&s);  // 重解释
    cout << ps << endl;  // 既然当作字符串类型,输出看一下结果 : 张三
    return 0;
}

在这里插入图片描述

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-05-18 17:26:01  更:2022-05-18 17:26:53 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 18:35:49-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码