云计算百科
云计算领域专业知识百科平台

C++入门(2)

一、引用(&)

1. 引用的概念和定义

• 本质:给已存在的变量取别名,编译器不会为引用变量开辟独立内存空间,与引用对象共用同一块内存。

• 语法格式:类型& 引用别名 = 引用对象;

• 示例:

int a = 0;
int& b = a;  // b是a的别名
int& c = a;  // 一个变量可多个引用
int& d = b;  // 给别名取别名,最终仍指向a
++d;         // 操作d等价于操作a
// 输出地址相同,验证共用内存
cout << &a << endl;
cout << &b << endl;
cout << &c << endl;
cout << &d << endl;

2. 引用的三大特性

1. 必须初始化:声明引用时必须绑定对象,不能单独声明(如int& ra; 编译报错)。

2. 一个变量可多个引用:同一变量可被多个引用别名指向。

3. 引用不可更改指向:一旦绑定某个对象,无法再绑定其他对象(后续赋值是修改对象值,而非改指向)。

• 示例:

int a = 10;
int& b = a;
int c = 20;
b = c;  // 不是改指向,是将c的值赋给a(b是a的别名)

3. 引用的使用场景

(1)引用传参(替代指针传参,简化语法)

• 作用:函数内修改实参,避免指针解引用的繁琐,可读性更高。

• 示例(交换函数):

void Swap(int& rx, int& ry) {
    int tmp = rx;
    rx = ry;
    ry = tmp;
}
int main() {
    int x = 0, y = 1;
    Swap(x, y);  // 直接传变量,无需取地址
    cout << x << " " << y << endl;
    return 0;
}

(2)引用做返回值(减少拷贝,提高效率)

• 作用:返回对象的别名,避免值返回的拷贝开销,可直接修改返回对象。

• 示例(栈顶元素返回):

typedef int STDataType;
typedef struct Stack {
    STDataType* a;
    int top;
    int capacity;
} ST;
// 引用返回栈顶元素,可直接修改
STDataType& STTop(ST& rs) {
    return rs.a[rs.top];
}
int main() {
    ST st1;
    STInit(st1);
    STPush(st1, 1);
    STTop(st1) += 10;  // 直接修改栈顶值
    cout << STTop(st1) << endl;
    return 0;
}

(3)指针引用(替代二级指针,简化链表操作)

• 作用:给指针变量取别名,无需二级指针即可修改指针本身。

• 示例(链表尾插):

typedef struct ListNode {
    int val;
    struct ListNode* next;
} LTNode, *PNode;
// 指针引用phead,直接修改头指针
void ListPushBack(PNode& phead, int x) {
    PNode newnode = (PNode)malloc(sizeof(LTNode));
    newnode->val = x;
    newnode->next = NULL;
    if (phead == NULL) {
        phead = newnode;  // 直接修改头指针
    } else {
        // 遍历尾插逻辑…
    }
}
int main() {
    PNode plist = NULL;
    ListPushBack(plist, 1);  // 直接传指针,无需传地址
    return 0;
}

4. const 引用(权限控制)

(1)核心规则

• 可引用const对象,必须用const引用(权限不能放大);

• const引用可引用普通对象(权限缩小,合法)。

(2)临时对象与const引用

• 表达式求值、类型转换会产生临时对象(编译器自动创建的未命名对象,具有常量性);

• 临时对象只能用const引用绑定,普通引用会编译报错。

• 示例:

const int a = 10;
// int& ra = a;  报错:权限放大(const→非const)
const int& ra = a;  // 合法

int b = 20;
const int& rb = b;  // 合法:权限缩小(非const→const)
// rb++;  报错:const引用不可修改

// 临时对象绑定(必须用const引用)
const int& rb = a * 3;  // a*3产生临时对象,const引用绑定
double d = 12.34;
const int& rd = d;      // 类型转换产生临时对象,const引用绑定

5. 引用与指针的核心区别

对比维度 引用 指针
内存占用 不开辟独立内存,共用对象内存 开辟独立内存(存地址) 
初始化 必须初始化 可声明后赋值(语法不强制) 
指向修改 绑定后不可改指向 可随时改指向
访问方式 直接访问对象,无需解引用 需解引用(*)访问对象 
空值 无空引用,更安全 可指向NULL/nullptr,易出空指针 
sizeof结果 引用类型的大小(如int&→4) 地址空间大小(32位4/64位8) 

二、inline 关键字(内联函数)

1. 核心概念

• 定义:inline修饰的函数为内联函数,编译时编译器会在调用处直接展开函数体,避免函数调用的栈帧开销,提高执行效率。

• 本质:是编译器建议,而非强制命令——编译器会根据函数复杂度(如代码长度、是否递归)决定是否展开,C++标准无强制展开规则。

2. 适用场景

• 适合:频繁调用、代码简短的函数(如简单的加减、取值函数);

• 不适合:递归函数、代码冗长的函数(编译器会自动忽略inline)。

3. 与C语言宏函数的对比

• 宏函数:预处理阶段文本替换,无类型检查,易出错(如括号缺失导致运算优先级问题);

• inline函数:编译阶段处理,有类型安全检查,语法与普通函数一致,替代宏函数更安全。

• 宏函数易错示例:

// 错误宏(无括号,优先级问题)
#define ADD(a,b) a+b
cout << ADD(1,2)*5 << endl;  // 展开为1+2*5=11,不符合预期
// 正确宏(加括号保证优先级)
#define ADD(a,b) ((a)+(b))
cout << ADD(1,2)*5 << endl;  // 展开为(1+2)*5=15,符合预期

4. inline函数的使用规范

1. 声明与定义不分离:若将inline函数声明放头文件、定义放源文件,链接时会报“无法解析外部符号”(内联展开后无函数地址,链接器找不到定义)。

◦ 错误示例:

// F.h(声明)
inline void f(int i);
// F.cpp(定义)
void f(int i) { cout << i << endl; }
// main.cpp(调用)
#include "F.h"
f(10);  // 链接报错:无法解析外部符号

2. Debug模式默认不展开:VS等编译器的Debug版本为方便调试,默认关闭inline展开,Release版本自动开启。

5. 代码示例

#include <iostream>
using namespace std;
// 内联函数:简单加法,适合展开
inline int Add(int x, int y) {
    int ret = x + y;
    ret += 1;
    return ret;
}
int main() {
    int ret = Add(1, 2);  // 编译时直接展开为int ret=1+2+1;
    cout << ret << endl;
    return 0;
}

三、nullptr(C++11空指针关键字)

1. 传统NULL的缺陷

• 本质:NULL是宏,C++中定义为0,C中定义为(void*)0;

• 问题:函数重载时,NULL会被优先匹配int参数版本,而非指针版本,违背空指针使用初衷。

• 示例:

void f(int x) { cout << "f(int x)" << endl; }
void f(int* ptr) { cout << "f(int* ptr)" << endl; }
int main() {
    f(NULL);  // 匹配f(int x),而非预期的f(int* ptr)
    f((int*)NULL);  // 强制转换才能匹配指针版本,繁琐
    return 0;
}

2. nullptr的优势

• 类型:C++11新增关键字,是特殊指针类型字面值,只能隐式转换为任意指针类型,不能转换为整数类型;

• 作用:完美表示空指针,避免NULL的类型歧义,重载时优先匹配指针参数。

• 示例:

void f(int x) { cout << "f(int x)" << endl; }
void f(int* ptr) { cout << "f(int* ptr)" << endl; }
int main() {
    f(nullptr);  // 直接匹配f(int* ptr),无需强制转换
    return 0;
}

3. 核心规则

• nullptr是指针类型,NULL是整数0(C++);

• 空指针定义优先用nullptr,替代NULL,避免类型歧义。

 

赞(0)
未经允许不得转载:网硕互联帮助中心 » C++入门(2)
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!