前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >快速从C过度C++(二):引用,内联函数,nullptr

快速从C过度C++(二):引用,内联函数,nullptr

作者头像
用户11029137
发布2025-03-07 10:16:33
发布2025-03-07 10:16:33
3900
代码可运行
举报
文章被收录于专栏:编程学习编程学习
运行总次数:0
代码可运行

📝前言: 本文章适合有一定C语言编程基础的读者浏览,主要介绍从C语言到C++过度,我们首先要掌握的一些基础知识,以便于我们快速进入C++的学习,为后面的学习打下基础。上一篇文章快速从C过度C++,我们讲述了namespace,C++的输入和输出,缺省参数,函数重载。 这篇文章主要介绍: 1,引用 2,内联函数 3,nullptr

一,引用

1. 引用的介绍

C++的引用是给变量取别名,编译器不会为引用变量开辟新的内存空间,它和它引用的变量共用一块内存空间。

定义引用:引用在定义时必须初始化,并且一旦初始化后,就不能再指向其他变量。

语法:使用 & 符号来声明引用。

示例

代码语言:javascript
代码运行次数:0
复制
int x = 10;
int &ref = x;  // ref 是 x 的引用
ref = 20;      // 修改 ref 也会修改 x
std::cout << x; // 输出 20

2. 引用的特点

  1. 必须初始化:引用在声明时必须初始化,不能先声明后赋值。
  2. 不可重新绑定:引用一旦绑定到一个变量,就不能再绑定到其他变量(即:不能改变指向)。
  3. 多个别名:一个变量可以有多个引用
  4. 无空引用:引用必须指向一个有效的对象,不能像指针那样可以为 nullptr
  5. 自动解引用:使用引用时不需要像指针那样使用 * 来解引用。

3. 引用的使用

3.1. 作为函数参数传递

引用常用于函数参数传递,特别是当你想在函数内部修改传入的变量时。

  • 示例
代码语言:javascript
代码运行次数:0
复制
void increment(int &num) {
    num++;
}

int main() {
    int a = 5;
    increment(a);
    std::cout << a; // 输出 6
    return 0;
}

在这里,numa的别名,所以修改了num就是真实的修改了a

3.2. 作为函数返回值

引用也可以作为函数的返回值,通常用于返回类成员变量或静态变量(即常量)。

  • 示例
代码语言:javascript
代码运行次数:0
复制
int& getValue() {
    static int value = 10;
    return value;
}

int main() {
    int &ref = getValue(); 引用接收常量
    ref = 20;
    std::cout << getValue(); // 输出 20
    return 0;
}

3.3. 权限放大错误

权限:只读,可读写… 下面三种情况,会生成一个临时变量存放结果,这个临时变量具有常性(只读性):

  1. 表达式返回
  2. 函数返回
  3. 类型转换(提升和截断都属于)

这个临时变量可以引用绑定,当被绑定后,就不会被销毁(生命周期) 但是,我们在绑定这个临时变量时要注意权限放大错误,如下:

代码语言:javascript
代码运行次数:0
复制
int main() {
	int a = 1;
	int b = 2;
	int &c = a + b;
	return 0;
}

出现权限放大错误,因为a + b返回时,会产生一个具有只读性的临时变量,但是企图用int类型来接受它,放大了权限,导致错误。权限可以缩小,但是不能放大。 类似的还有:

代码语言:javascript
代码运行次数:0
复制
int main() {
	double a = 3.14;
	int &b = int(a);
	return 0;
}
代码语言:javascript
代码运行次数:0
复制
int ADD(int a, int b) {
	return a + b;
}
int main() {
	int& c = ADD(1, 2);
	return 0;
}
代码语言:javascript
代码运行次数:0
复制
	const int a = 10;
	int& ra = a;

4. const引用

在C++中,const 引用(常量引用)是一种特殊的引用类型,它允许你通过引用的方式访问一个对象,但不能通过该引用修改对象的值。修改引用对象,被引用对象也被修改

4.1. const引用的基本语法

const 引用通过在引用声明前加上 const 关键字来定义。它的语法如下:

代码语言:javascript
代码运行次数:0
复制
const T& ref = obj;
  • T 是类型。
  • ref 是引用的名称。
  • obj 是被引用的对象。

示例:

代码语言:javascript
代码运行次数:0
复制
int x = 10;
const int& ref = x; // ref 是 x 的 const 引用

4.2. const 引用的特性

只读性:通过 const 引用,只能读取对象的值,不能修改对象的值。

代码语言:javascript
代码运行次数:0
复制
int x = 10;
const int& ref = x;
std::cout << ref; // 正确:读取值
ref = 20;         // 错误:不能通过 const 引用修改值

绑定到临时对象const 引用可以绑定到临时对象(右值),并且会延长临时对象的生命周期。(因为const也只具有只读性,不会有权限放大的问题)

代码语言:javascript
代码运行次数:0
复制
const int& ref = 42; // 正确:绑定到临时对象

避免拷贝const 引用可以避免不必要的对象拷贝,特别是在函数参数传递时。

代码语言:javascript
代码运行次数:0
复制
void printValue(const std::string& str) {
    std::cout << str;
}

int main() {
    std::string s = "Hello, World!";
    printValue(s); // 避免拷贝
    return 0;
}

4.3. const引用的常见用途
4.3.1. 函数参数传递

const 引用常用于函数参数传递,特别是当函数不需要修改参数的值时。这种方式可以避免不必要的拷贝,同时保证参数的值不会被意外修改。

示例

代码语言:javascript
代码运行次数:0
复制
void printValue(const int& value) {
    std::cout << value;
}

int main() {
    int x = 10;
    printValue(x); // 传递 x 的 const 引用
    return 0;
}
4.3.2. 绑定到临时对象

const 引用可以绑定到临时对象(右值),并且会延长临时对象的生命周期。

示例

代码语言:javascript
代码运行次数:0
复制
const std::string& getString() {
    return "Hello, World!"; // 返回临时对象的 const 引用
}

int main() {
    const std::string& ref = getString(); // 延长临时对象的生命周期
    std::cout << ref; // 输出 "Hello, World!"
    return 0;
}
4.3.3. 避免权限放大错误

const 引用可以防止权限放大错误,即防止将只读对象转换为可读写对象。

示例

代码语言:javascript
代码运行次数:0
复制
int getValue() {
    return 42; // 返回临时对象
}

int main() {
    const int& ref = getValue(); // 正确:绑定到临时对象的 const 引用
    // int& ref = getValue();    // 错误:权限放大错误
    return 0;
}

4.4. const引用与普通引用的区别

特性

const 引用

普通引用

是否可修改对象

不可修改

可修改

能否绑定到临时对象

可以

不可以

权限

只读

可读写

常见用途

函数参数传递、绑定临时对象

需要修改对象时使用


5. 引用与指针的关系

  • 语法概念上,引用就是取别名,不开空间,指针是存储一个地址,要开空间
  • 底层,引用是用指针实现的
  • 引用定义必须初始化,指针只是建议初始化,但是非必须
  • 引用绑定一个对象以后不能修改,指针可以
  • sizeof的含义不同,引用结果大小为引用类型的大小,指针始终为地址空间所占字节个数
  • 指针容易出现空指针和野指针

二,内联函数inline

1. 宏函数

宏函数(通常也称为宏定义)是在编程中一种预处理指令,它允许你定义一个标识符来代表一段代码片段。在编译之前,预处理器会将源文件中所有使用该标识符的地方替换为对应的代码片段。

代码语言:javascript
代码运行次数:0
复制
#define 宏名(参数列表) 替换文本

注意: 1,替换文本后面不接; 2,替换文本中要多用括号来体现优先级,不然容易出现替换后的优先级问题

示例:

代码语言:javascript
代码运行次数:0
复制
#define ADD(x, y) ((x) - (y))

2. 内敛函数

内联函数(Inline Function) 是C++中的一种函数优化机制,通过在函数定义前加上 inline 关键字,建议编译器将函数调用处直接替换为函数体代码,以减少函数调用的开销。

2.1. 主要特点
  1. 减少开销:避免函数调用的压栈、跳转和返回操作,提升效率。
  2. 代码膨胀:函数体被直接插入调用处,可能增加生成的可执行文件大小。
  3. 编译器决定inline 只是建议,编译器有权决定是否内联,通常适用于简单、频繁调用的函数。当函数过于复杂时,编译器依旧会当做普通的函数来运行,开辟栈帧。
  4. 调试困难:内联函数在调试时可能难以跟踪。
2.2. 使用场景
  • 短小函数:适合代码简单、调用频繁的函数。递归或复杂函数不适合内联。
  • 性能关键代码:在需要优化性能时使用。
  • 替代宏:内联函数比宏更安全,能进行类型检查。

示例:

代码语言:javascript
代码运行次数:0
复制
#include <iostream>
using namespace std;

inline int add(int a, int b) {
    return a + b;
}

int main() {
    int result = add(3, 4);  // 可能被替换为 int result = 3 + 4;
    cout << "Result: " << result << endl;
    return 0;
}

三,nullptr

1. nullptr 和 NULL 的区别

nullptr 是 C++11 引入的关键字,用于表示空指针。它解决了 C 语言中 NULL 的一些问题,提供了更安全、更清晰的空指针表示方式。

特性

nullptr (C++11)

NULL (C/C++)

类型

是 std::nullptr_t 类型,可以隐式转换为任意指针类型

通常是 0 或 (void*)0,是一个宏定义

类型安全

类型安全,不会与整数类型混淆

可能被误认为是整数类型(如 int)

重载函数解析

能正确区分指针和整数重载

可能导致重载函数解析错误

代码清晰性

明确表示空指针,语义清晰

语义不够明确,可能被误解为整数 0


2. 为什么需要 nullptr?

类型安全问题

在 C++ 中,NULL 通常被定义为 0(void*)0,这可能导致类型混淆。例如:

代码语言:javascript
代码运行次数:0
复制
void foo(int);
void foo(char*);

foo(NULL);  // 调用 foo(int),而不是 foo(char*)

使用 nullptr 可以避免这种问题:

代码语言:javascript
代码运行次数:0
复制
foo(nullptr);  // 明确调用 foo(char*)

重载函数解析

  • NULL 可能被当作整数 0,导致调用错误的重载函数。nullptr 明确表示指针类型,能正确匹配指针重载。

代码清晰性

  • nullptr 明确表示空指针,提高了代码的可读性和语义清晰性。

C++ 类型系统的改进

  • nullptrstd::nullptr_t 类型,可以隐式转换为任意指针类型,但不能转换为整数类型,增强了类型检查。

示例:

代码语言:javascript
代码运行次数:0
复制
#include <iostream>
using namespace std;

void func(int) {
    cout << "Called func(int)" << endl;
}

void func(char*) {
    cout << "Called func(char*)" << endl;
}

int main() {
    func(0);         // 调用 func(int)
    func(NULL);      // 可能调用 func(int),取决于 NULL 的定义
    func(nullptr);   // 明确调用 func(char*)

    int* ptr = nullptr;  // 正确:nullptr 可以赋值给指针
    // int num = nullptr; // 错误:nullptr 不能赋值给整数类型

    return 0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-03-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一,引用
    • 1. 引用的介绍
    • 2. 引用的特点
    • 3. 引用的使用
      • 3.1. 作为函数参数传递
      • 3.2. 作为函数返回值
      • 3.3. 权限放大错误
    • 4. const引用
      • 4.1. const引用的基本语法
      • 4.2. const 引用的特性
      • 4.3. const引用的常见用途
      • 4.4. const引用与普通引用的区别
    • 5. 引用与指针的关系
  • 二,内联函数inline
    • 1. 宏函数
    • 2. 内敛函数
      • 2.1. 主要特点
      • 2.2. 使用场景
  • 三,nullptr
    • 1. nullptr 和 NULL 的区别
    • 2. 为什么需要 nullptr?
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档