C++基础篇(2)(下)

简介: C++基础篇(2)(下)

C++基础篇(2)(下):https://developer.aliyun.com/article/1624926


3.引用

3.1引用的概念和定义

在 C++ 中,引用是一个变量的别名。一旦一个引用被初始化为指向一个对象,它就不能被重新绑定到另一个对象。这与指针不同,指针可以在任何时候指向不同的对象。

引用的概念

  • 别名:引用为另一个变量提供了一个额外的名字,它和原变量指向相同的内存位置。
  • 不可变性:一旦引用被初始化,它就不能被重新赋值为另一个变量的引用。
  • 无需解引用:使用引用时,不需要像指针一样使用 * 操作符来访问引用的值。
  • 效率:引用在传递参数时可以避免不必要的复制,特别是对于大型对象来说,使用引用可以提高效率。

引用的定义

引用在 C++ 中是这样定义的:

类型 &引用名 = 原变量名;

一些有趣的实例:

比如:水浒传中李逵,宋江叫"铁牛",江湖上人称"黑旋风";林冲,外号豹子头;

这里,类型 是原变量的类型,& 符号用于声明引用,引用名 是你给引用起的名字,而 原变量名 是已经存在的变量。

#include <iostream>
using namespace std;
int main() {
  int a = 520;
  int& b = a;
  int& c = a;
  int& d = b;
  ++d;
// 引⽤:b和c是a的别名
  cout << &a << endl;
  cout << &b << endl;
  cout << &c << endl;
// 也可以给别名b取别名,d相当于还是a的别名
  cout << &d << endl;
//地址,值都是一样的
  cout << a << endl;
  cout << b << endl;
  cout << c << endl;
  cout << d << endl;
  return 0;
}

3.2引用的特性

• 引用在定义时必须初始化

• 一个变量可以有多个引用

• 引用一旦引用一个实体,再不能引用其他实体

#include<iostream>
using namespace std;
int main()
{
  int a = 10;
  // 编译报错:“ra”: 必须初始化引⽤
  //int& ra;
  int& b = a;
  int c = 20;
  // 这⾥并⾮让b引⽤c,因为C++引⽤不能改变指向,
  // 这⾥是⼀个赋值
  b = c;
  cout << a << endl;
  cout << b << endl;
  cout << c << endl;
  b = 30;
  cout << &a << endl;
  cout << &b << endl;
  cout << &c << endl;
  cout << a << endl;
  cout << b << endl;
  cout << c << endl;
  return 0;
}

3.3引用的使用

1.引用在实践中主要是于引用传参和引用做返回值中减少拷贝提高效率和改变引用对象时同时改变被引用对象。

2.引用传参跟指针传参功能是类似的,引用传参相对更方便一些。

3.引用返回值的场景相对比较复杂,小编实力有限,以后等知识丰富了再会详细讲解。

4.引用和指针在实践中相辅相成,功能有重叠性,但是各有特点,互相不可替代。C++的引用跟其他语言的引用(如Java)是有很大的区别的,除了用法,最大的点,C++引用定义后不能改变指向,java的引用可以改变指向。

5.一些主要用C代码实现版本数据结构教材中,使用C++引用替代指针传参,用的是简化程序,避开复杂的指针。

代码实例:

#include <iostream>
using namespace std;
void Swap(int& x, int& y) {
  int temp = x;
  x = y;
  y = temp;
}
int main() {
  int x = 520, y = 1314;
  cout << x << " " << y << endl;
  Swap(x, y);
  cout << x << " " << y << endl;
 
  return 0;
}

#include<iostream>
#include <assert.h>
#include <stdlib.h> 
 
using namespace std;
typedef int STDataType;
typedef struct Stack {
    STDataType* a;
    int top;
    int capacity;
} ST;
 
void STInit(ST& rs, int n = 4) {
    rs.a = (STDataType*)malloc(n * sizeof(STDataType));
    rs.top = 0; // 栈顶初始化为 0,表示栈为空
    rs.capacity = n;
}
 
void STPush(ST& rs, STDataType x) {
    // 满了,扩容
    if (rs.top == rs.capacity) {
        printf("扩容\n");
        int newcapacity = rs.capacity == 0 ? 4 : rs.capacity * 2;
        STDataType* tmp = (STDataType*)realloc(rs.a, newcapacity * sizeof(STDataType));
        if (tmp == NULL) {
            perror("realloc fail");
            return;
        }
        rs.a = tmp;
        rs.capacity = newcapacity;
    }
    rs.a[rs.top] = x; 
    rs.top++; // 栈顶指针上移
}
 
int& STTop(ST& rs) {
    assert(rs.top > 0); // 确保栈不为空
    return rs.a[rs.top - 1]; // 返回栈顶元素的引用
}
 
int main() {
    ST st1;
    STInit(st1);
    STPush(st1, 1);
    STPush(st1, 2);
    cout << STTop(st1) << endl; // 输出栈顶元素 2
    STTop(st1) += 10; // 通过引用修改栈顶元素
    cout << STTop(st1) << endl; // 输出修改后的栈顶元素 12
    return 0;
}

3.4const引用

在 C++ 中,const 引用是一种特殊类型的引用,它被用来引用一个对象,同时保证这个引用不会修改所引用的对象。这种引用通常用于函数参数,以允许函数读取传递的对象,但不允许通过引用修改它。

以下是 const 引用的几个关键点:

声明 const 引用

const 类型 &引用名 = 引用的对象;

这里,类型 是被引用对象的类型,引用名 是你给引用起的名字,而 引用的对象 是你想要引用的实际对象。

使用 const 引用的好处

  • 保护数据不被修改:通过 const 引用,你可以确保传递给函数的参数不会被函数修改。
  • 可以引用临时对象和字面量const 引用可以引用右值(如字面量或临时对象),这是非 const 引用无法做到的。
  • 可以与任何类型的对象兼容:只要类型可以转换为 const 引用的类型,就可以创建 const 引用。

示例

不需要注意的是类似 int& rb = a*3; double d = 12.34; int& rd = d; 这样一些场景下a*3的和结果保存在一个临时对象中, int& rd = d 也是类似,在类型转换中会产生临时对象存储中间值,也就是时,rb和rd引用的都是临时对象,而C++规定临时对象具有常性,所以这里就触发了权限放大,必须要用常引用才可以。

int main()
{
const int a = 10;
// 编译报错:error C2440: “初始化”: ⽆法从“const int”转换为“int &”
// 这⾥的引⽤是对a访问权限的放⼤
//int& ra = a;
// 这样才可以
const int& ra = a;
// 编译报错:error C3892: “ra”: 不能给常量赋值
//ra++;
// 这⾥的引⽤是对b访问权限的缩⼩
int b = 20;
const int& rb = b;
// 编译报错:error C3892: “rb”: 不能给常量赋值
//rb++;
return 0;
}
#include<iostream>
using namespace std;
int main()
{
int a = 10;
const int& ra = 30;
// 编译报错: “初始化”: ⽆法从“int”转换为“int &”
// int& rb = a * 3;
const int& rb = a*3;
double d = 12.34;
// 编译报错:“初始化”: ⽆法从“double”转换为“int &”
// int& rd = d;
const int& rd = d;
return 0;
}
#include <iostream>
using namespace std;
 
void print(const int& x) {
    cout << x << endl;
    // x = 5; // 错误:不能通过 const 引用修改对象
}
 
int main() {
    int a = 10;
    const int& ref = a; // 创建一个对 a 的 const 引用
    // ref = 20; // 错误:不能通过 const 引用修改对象
 
    print(a); // 正确:传递 int
    print(20); // 正确:传递字面量,通过 const 引用允许
 
    return 0;
}

注释前的错误:

正确运行结果:

注意事项

  • 一旦 const 引用被初始化,它就不能再引用其他对象。
  • const 引用不能引用非 const 对象的地址,如果需要引用非 const 对象,必须显式地声明非 const 引用。

总之,const 引用在 C++ 中是一种非常有用的特性,它不仅提供了对数据的保护,还增加了代码的灵活性和安全性。

4.指针和引用的关系

C++中指针和引用就像两个性格迥异的亲兄弟,指针是哥哥,引用是弟弟,在实践中他们相辅相成,能有重叠性,但是各有自己的特点,互相不可替代。

• 语法概念上引用是一个变量的取别名不开空间,指针是存储一个变量地址,要开空间。

• 引用在定义时必须初始化,指针建议初始化,但是语法上不是必须的。

• 引用在初始化时引用一个对象后,就不能再引用其他对象;而指针可以在不断地改变指向对象。

• 引用可以直接访问指向对象,指针需要解引用才是访问指向对象。

• sizeof中含义不同,引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节,64位下是8byte)

• 指针很容易出现空指针和野指针的问题,引用很少出现,引用使用起来相对更安全一些。

结束语

本篇博客也就到此结束啦,C++ 的入门也差不多了,下个阶段我们将步入类和对象的学习!!!

最后支持小编的友友和大佬们点个赞吧,也欢迎大家在评论区多多交流,感谢大家的支持!!!



目录
相关文章
|
12月前
|
存储 编译器 C#
C#基础补充
C#基础补充
58 0
|
SQL 关系型数据库 MySQL
通用分页的详细讲解看这一篇就够了(内含源码)(上)
通用分页的详细讲解看这一篇就够了(内含源码)
107 0
|
1天前
|
编译器 程序员 C++
C++基础篇(2)(上)
C++基础篇(2)(上)
10 0
|
5月前
|
算法 图计算
什么是图计算?请简要解释其概念和特点。
什么是图计算?请简要解释其概念和特点。
242 0
|
11月前
|
存储 Kubernetes 网络协议
k8s教程(基础篇)-基本概念和术语(上)
k8s教程(基础篇)-基本概念和术语(上)
123 0
|
SQL Java 关系型数据库
通用分页的详细讲解看这一篇就够了(内含源码)(下)
通用分页的详细讲解看这一篇就够了(内含源码)(下)
72 0
|
编译器 C语言 C++
C++入门(一)(上)
C语言是结构化和模块化的语言,适合处理较小规模的程序。对于复杂的问题,规模较大的程序,需要高度 的抽象和建模时,C语言则不合适。为了解决软件危机, 20世纪80年代, 计算机界提出了OOP(object oriented programming:面向对象)思想,支持面向对象的程序设计语言应运而生。
97 0
C++入门(一)(上)
|
存储 并行计算 测试技术
【CUDA学习笔记】第五篇:内存以及案例解释(附案例代码下载方式)(二)
【CUDA学习笔记】第五篇:内存以及案例解释(附案例代码下载方式)(二)
165 0
【CUDA学习笔记】第五篇:内存以及案例解释(附案例代码下载方式)(二)
运算符(较为基础,基础篇)(二)
运算符(较为基础,基础篇)(二)
58 0
运算符(较为基础,基础篇)(一)
运算符(较为基础,基础篇)(一)
61 0