【C/C++】C++引用和指针的对比
🔥个人主页:艾莉丝努力练剑
❄专栏传送门:《C语言》、《数据结构与算法》、C语言刷题12天IO强训、LeetCode代码强化刷题、C/C++干货分享&学习过程记录
🍉学习方向:C/C++方向
⭐️人生格言:为天地立心,为生民立命,为往圣继绝学,为万世开太平
前言:本专栏记录了博主C++从初阶到高阶完整的学习历程,会发布一些博主学习的感悟、碰到的问题、重要的知识点,和大家一起探索C++这门程序语言的奥秘。这个专栏将记录博主C++语法、高阶数据结构、STL的学习过程,正所谓“万丈高楼平地起”嘛,我们话不多说,继续进行C++阶段的学习。本文我们不讲C++主线的内容,我们来拓展一下或者说整理一下我们学习时C/C++时经常会提到的一些专有名词,例如形参、实参,显式类型转换和隐式类型转换类型转换,内置类型等等。
C++的两个参考文档:
老朋友(非官方文档):cplusplus
官方文档(同步更新):cppreference
目录
正文
一、引用的基本概念
1、定义与声明
2、引用与指针的区别
二、引用的主要用途
1、函数参数传递
2、函数返回值
三、const引用
1、常量引用
2、函数参数中的const引用
四、引用与右值引用(C++11)
1、左值引用 vs 右值引用
2、移动语义
五、引用折叠规则(C++11)
六、特殊引用情况
1、引用数组
2、指向指针的引用
七、引用使用的最佳实践
八、常见错误
1、 返回局部变量引用
2、未初始化的引用
3、引用NULL
九、详解C++引用
引用基础
1、基本引用示例
2、引用与指针对比
(二)函数中的引用
1、引用参数示例
2、返回引用示例
(三)const引用
1、const引用基础
2、const引用参数
(四)右值引用(C++11)
1、基本右值引用
2、移动语义示例
(五)高级引用用法
1、引用数组
2、指向指针的引用
(六)综合应用示例
1、链式调用
2、引用作为类成员
结尾
正文
博主之前写过C++引用相关的内容,只不过那是在C++初识部分介绍的,比较简略:
【C/C++】初识C++(二):深入详解缺省参数(默认参数)函数重载、引用(重头戏)
【C/C++】初识C++(三):C++入门内容收尾——const引用,指针和引用关系梳理,inline(内联函数),nullptr替代NULL
引用是C++中一种重要的特性,它提供了对变量的别名机制,使得我们可以用不同的名称访问同一块内存空间。下面全面介绍C++引用的核心知识点。
一、引用的基本概念
1、定义与声明
int num = 10;
int &ref = num; // ref是num的引用
-
引用必须在声明时初始化
-
引用一旦绑定到一个变量,就不能再绑定到其他变量
-
引用不是对象,不占用额外存储空间(编译器实现可能不同)
2、引用与指针的区别
特性 | 引用 | 指针 |
---|---|---|
初始化要求 | 必须初始化 | 可以不初始化 |
可修改性 | 不能重新绑定 | 可以指向不同对象 |
空值 | 不能为空 | 可以为NULL/nullptr |
操作方式 | 直接使用 | 需要解引用(*) |
内存占用 | 通常不占额外空间 | 占用指针大小的空间 |
二、引用的主要用途
1、函数参数传递
void swap(int &a, int &b) {int temp = a;a = b;b = temp;
}
-
避免拷贝大对象的开销
-
允许函数修改实参的值
-
比指针更安全(不能为null)
2、函数返回值
int &getMax(int &a, int &b) {return a > b ? a : b;
}int main() {int x = 5, y = 10;getMax(x, y) = 20; // 修改了y的值
}
-
可以返回引用实现左值调用
-
不能返回局部变量的引用(会导致悬空引用)
三、const引用
1、常量引用
const int &ref = 42; // 合法:常量引用可以绑定到字面量
2、函数参数中的const引用
void print(const std::string &str) {// 不能通过str修改原对象std::cout << str;
}
-
避免不必要的拷贝
-
保证函数内不会修改参数
-
可以接受临时对象和字面量
四、引用与右值引用(C++11)
1、左值引用 vs 右值引用
int a = 10;
int &lref = a; // 左值引用
int &&rref = 20; // 右值引用
2、移动语义
class MyString {
public:// 移动构造函数MyString(MyString &&other) noexcept {data = other.data;other.data = nullptr;}
};
五、引用折叠规则(C++11)
template<typename T>
void func(T&& param) { // 万能引用// 根据传入参数决定引用类型
}int a = 10;
func(a); // T&
func(10); // T&&
六、特殊引用情况
1、引用数组
int arr[5] = {1, 2, 3, 4, 5};
int (&refArr)[5] = arr; // 数组的引用
2、指向指针的引用
int *ptr = nullptr;
int *&refPtr = ptr; // 指向指针的引用
七、引用使用的最佳实践
函数参数优先使用const引用传递大对象
需要修改参数时使用普通引用
避免返回局部变量的引用
明确区分左值引用和右值引用
谨慎使用引用作为类成员(可能引入生命周期问题)
八、常见错误
1、 返回局部变量引用
int &badFunc() {int local = 10;return local; // 错误!
}
2、未初始化的引用
int &ref; // 错误:必须初始化
3、引用NULL
int &ref = NULL; // 错误
引用是C++强大而独特的特性,正确使用引用可以写出更高效、更安全的代码,但同时需要注意其特性和限制以避免潜在问题。
九、详解C++引用
引用基础
1、基本引用示例
#include <iostream>
using namespace std;int main() {int original = 42;int &ref = original; // 引用声明和初始化cout << "original: " << original << endl; // 42cout << "ref: " << ref << endl; // 42ref = 100; // 通过引用修改值cout << "after change:" << endl;cout << "original: " << original << endl; // 100cout << "ref: " << ref << endl; // 100// 验证它们共享同一地址cout << "Address of original: " << &original << endl;cout << "Address of ref: " << &ref << endl; // 相同地址
}
2、引用与指针对比
void compareRefAndPointer() {int x = 10;// 引用方式int &ref = x;ref = 20; // 直接使用// 指针方式int *ptr = &x;*ptr = 30; // 需要解引用cout << "x after ref change: " << x << endl;cout << "x after ptr change: " << x << endl;// 尝试重新绑定int y = 50;// ref = y; // 错误!不能重新绑定引用ptr = &y; // 指针可以重新指向
}
(二)函数中的引用
1、引用参数示例
// 交换两个变量的值
void swap(int &a, int &b) {int temp = a;a = b;b = temp;
}void testSwap() {int x = 10, y = 20;cout << "Before swap: x=" << x << ", y=" << y << endl;swap(x, y);cout << "After swap: x=" << x << ", y=" << y << endl;
}
2、返回引用示例
// 返回数组元素的引用
int &getElement(int arr[], int index) {return arr[index];
}void testReturnRef() {int numbers[] = {10, 20, 30, 40, 50};// 获取引用并修改getElement(numbers, 2) = 100;cout << "Modified array: ";for (int num : numbers) {cout << num << " ";}cout << endl;// 错误示例:返回局部变量引用/*int &badRef() {int local = 42;return local; // 警告:返回局部变量引用}*/
}
(三)const引用
1、const引用基础
void constRefDemo() {int a = 10;const int &ref1 = a; // 合法// ref1 = 20; // 错误:不能通过const引用修改const int b = 20;const int &ref2 = b; // 合法// 绑定到临时对象const int &ref3 = 30; // 合法cout << "ref3: " << ref3 << endl;
}
2、const引用参数
void printLargeObject(const string &str) {cout << str << endl;// str[0] = 'A'; // 错误:不能修改
}void testConstRefParam() {string longStr(1000, 'x'); // 大字符串printLargeObject(longStr); // 避免拷贝// 可以接受临时对象printLargeObject("Temporary string");
}
(四)右值引用(C++11)
1、基本右值引用
void rvalueRefDemo() {int &&rref1 = 10; // 右值引用int x = 10;// int &&rref2 = x; // 错误:不能绑定左值rref1 = 20; // 可以修改cout << "rref1: " << rref1 << endl;
}
2、移动语义示例
class StringWrapper {char *data;
public:// 构造函数explicit StringWrapper(const char *str = "") {data = new char[strlen(str) + 1];strcpy(data, str);}// 移动构造函数StringWrapper(StringWrapper &&other) noexcept {data = other.data;other.data = nullptr;}// 移动赋值运算符StringWrapper &operator=(StringWrapper &&other) noexcept {if (this != &other) {delete[] data;data = other.data;other.data = nullptr;}return *this;}~StringWrapper() {delete[] data;}void print() const {cout << (data ? data : "null") << endl;}
};void testMoveSemantics() {StringWrapper sw1("Hello");StringWrapper sw2 = std::move(sw1); // 使用移动构造函数cout << "After move:" << endl;cout << "sw1: ";sw1.print(); // 输出 nullcout << "sw2: ";sw2.print(); // 输出 Hello
}
(五)高级引用用法
1、引用数组
void refArrayDemo() {int arr[3] = {1, 2, 3};int (&refArr)[3] = arr; // 数组的引用refArr[1] = 20; // 修改原数组cout << "Original array: ";for (int n : arr) {cout << n << " ";}cout << endl;
}
2、指向指针的引用
void pointerRefDemo() {int x = 10;int *ptr = &x;int *&refPtr = ptr; // 指向指针的引用*refPtr = 20; // 修改x的值cout << "x: " << x << endl;int y = 30;refPtr = &y; // 修改指针指向*refPtr = 40;cout << "y: " << y << endl;
}
(六)综合应用示例
1、链式调用
class Counter {int count;
public:Counter() : count(0) {}Counter &increment() {++count;return *this;}Counter &decrement() {--count;return *this;}int get() const { return count; }
};void testChaining() {Counter c;c.increment().increment().decrement();cout << "Count: " << c.get() << endl; // 输出 1
}
2、引用作为类成员
class Logger {ostream &out;
public:explicit Logger(ostream &os = cout) : out(os) {}void log(const string &msg) {out << msg << endl;}
};void testLogger() {Logger consoleLogger;consoleLogger.log("This goes to console");ofstream file("log.txt");Logger fileLogger(file);fileLogger.log("This goes to file");
}
博主展示的这些代码示例,涵盖了C++引用的各种用法,从基础到高级特性。通过实际运行这些代码,可以更深入地理解引用的工作原理和应用场景。
结尾
往期回顾:
【C/C++】形参、实参相关内容整理
【C/C++】Dev-C++的安装与使用以及快捷键整理
【日常问题解决方案】VS2022不小心解决方案资源管理器把关掉了怎么办
VS2022进行监视功能的步骤
结语:本文内容到这里就全部结束了。本文我们重新整理了C++引用和指针相关的内容。