C++ 入门必看:引用怎么用?inline 和 nullptr 是什么?

C++ 入门必看:引用(Reference)、inline、nullptr 详解

这三个内容都是 C++ 非常核心、非常常用的特性,而且是新手最容易混淆但又必须搞清楚的基础点。下面用最直白的方式把它们讲透。

1. 引用(Reference)—— C++ 最有特色的特性之一

一句话定义
引用是变量的别名,它不是一个独立的对象,而是某个已有变量的另一个名字。

最关键的几句话

  • 引用必须在定义时初始化,且一生只能绑定一个变量(不能改绑)
  • 对引用赋值 = 修改它所引用的那个变量
  • 引用本身不占额外内存(编译器通常优化为指针,但你不用关心)

基本写法对比

int a = 10;

// 指针方式(C 风格)
int* p = &a;
*p = 20;           // 修改 a

// 引用方式(C++ 风格)
int& r = a;        // r 是 a 的别名
r = 30;            // 其实就是在修改 a

std::cout << a << '\n';   // 输出 30

常用场景(必须记住这几种用法)

  1. 函数参数传引用(最常见用法,避免拷贝)
// 低效:每次调用都拷贝整个结构体
void swap_by_value(MyBigStruct x, MyBigStruct y) { ... }

// 高效:只传引用,不拷贝
void swap(MyBigStruct& x, MyBigStruct& y) {
    MyBigStruct temp = x;
    x = y;
    y = temp;
}
  1. 函数返回引用(常用于链式调用、返回对象本身)
class StringBuilder {
    std::string s;
public:
    StringBuilder& append(const std::string& str) {
        s += str;
        return *this;           // 返回自身引用
    }
};

int main() {
    StringBuilder sb;
    sb.append("hello").append(" ").append("world");  // 链式调用
}
  1. const 引用(最安全、最常用的参数传递方式)
void print(const std::string& str) {   // 既不拷贝,又不允许修改
    std::cout << str << '\n';
}

const 引用可以绑定临时对象(这是 C++ 非常重要的规则)

print("hello");          // 合法!临时字符串被绑定到 const 引用上

引用 vs 指针 快速对比(面试必考)

特性引用 (Reference)指针 (Pointer)
是否必须初始化可以是 nullptr
是否可以改指向不可以(一生一绑)可以改指向其他变量
是否可以为空不可以(没有空引用)可以是 nullptr
语法像普通变量使用需要 * 和 &
安全性更安全(无空指针问题)容易空指针、野指针
典型用途函数参数、返回、别名动态内存、链表、数组、可能为空

新手口诀
能用引用就用引用,能用 const 引用就用 const 引用。

2. inline 关键字(内联函数)

一句话理解
告诉编译器:“你可以把这个函数的代码直接嵌入调用处,而不是真的去调用”

现代 C++ 中 inline 的真实作用(非常重要):

  1. 最主要作用:允许在头文件中定义函数(解决多重定义问题)
  2. 次要作用:提示编译器进行内联优化(但编译器可以忽略)

经典用法(头文件里定义小函数)

// utils.h
#pragma once

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

inline double square(double x) {
    return x * x;
}

为什么用 inline?

  • 如果没有 inline,在多个 .cpp 文件中包含同一个头文件,会导致多次定义(ODR 违反,链接错误)
  • 加了 inline 后,编译器允许在每个翻译单元都生成一份定义,链接器最终合并

现代 C++ 中 inline 的使用建议(2025–2026 主流做法)

  • 小而简单的函数(1–3 行) → 直接写在头文件 + inline
  • 模板函数 → 默认就是 inline(不用写)
  • 成员函数在类内定义 → 自动 inline
  • 大函数、复杂函数 → 不要加 inline(反而可能降低性能)

常见误区
inline 不保证一定内联
现代编译器(O2/O3 优化)会自己决定是否内联,inline 关键字只是允许在头文件定义而已。

3. nullptr(C++11 引入)

一句话理解
nullptr 是专门表示空指针的字面值,类型是 std::nullptr_t,比 NULL 更安全、更清晰。

为什么 C++ 需要 nullptr?

C 时代用 NULL 表示空指针,但 NULL 其实是 0(整数):

void foo(int x)    { std::cout << "int\n"; }
void foo(char* p)  { std::cout << "pointer\n"; }

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

nullptr 的优势

foo(nullptr);   // 明确调用 foo(char*),类型安全

int* p1 = NULL;     // 合法但不推荐
int* p2 = nullptr;  // 推荐写法

// 重载解析更准确
if (ptr == nullptr)  // 清晰、安全

典型使用场景

// 1. 指针初始化
int* p = nullptr;

// 2. 函数参数默认值
void process(int* ptr = nullptr);

// 3. 与智能指针配合
std::unique_ptr<int> up = nullptr;

// 4. 避免 NULL 的二义性
foo(0);        // 调用 int 版本
foo(nullptr);  // 调用指针版本

总结:三者一句话口诀

  • 引用:变量的别名,一生一绑,函数参数首选 const 引用
  • inline:允许头文件定义函数 + 提示内联(现代更多是前者)
  • nullptr:专用的空指针字面值,比 NULL 类型安全

新手进阶建议(强烈推荐的写法习惯):

// 1. 函数参数尽量用 const 引用
void print(const std::string& s);

// 2. 小函数写在头文件 + inline
inline bool is_even(int n) { return n % 2 == 0; }

// 3. 所有指针初始化、比较都用 nullptr
int* ptr = nullptr;
if (ptr == nullptr) { ... }

如果你现在能熟练写出下面三种写法,就说明你已经入门了:

void func(const std::string& s = "");          // const 引用 + 默认值
inline int square(int x) { return x * x; }     // inline 小函数
int* ptr = nullptr;                            // 安全空指针

有哪一部分还觉得模糊?
想看更多实际例子(比如引用在类设计、模板中的用法,或者 inline 在不同编译器下的真实效果),可以告诉我,我继续展开。

文章已创建 4547

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部