📝前言:
本文章适合有一定C语言编程基础的读者浏览,主要介绍从C语言到C++过度,我们首先要掌握的一些基础知识,以便于我们快速进入C++的学习,为后面的学习打下基础。上一篇文章快速从C过度C++,我们讲述了namespace
,C++的输入和输出,缺省参数,函数重载。
这篇文章主要介绍:
1,引用
2,内联函数
3,nullptr
C++的引用是给变量取别名,编译器不会为引用变量开辟新的内存空间,它和它引用的变量共用一块内存空间。
定义引用:引用在定义时必须初始化,并且一旦初始化后,就不能再指向其他变量。
语法:使用 &
符号来声明引用。
示例:
int x = 10;
int &ref = x; // ref 是 x 的引用
ref = 20; // 修改 ref 也会修改 x
std::cout << x; // 输出 20
nullptr
。*
来解引用。引用常用于函数参数传递,特别是当你想在函数内部修改传入的变量时。
void increment(int &num) {
num++;
}
int main() {
int a = 5;
increment(a);
std::cout << a; // 输出 6
return 0;
}
在这里,num
是a
的别名,所以修改了num
就是真实的修改了a
引用也可以作为函数的返回值,通常用于返回类成员变量或静态变量(即常量)。
int& getValue() {
static int value = 10;
return value;
}
int main() {
int &ref = getValue(); 引用接收常量
ref = 20;
std::cout << getValue(); // 输出 20
return 0;
}
权限:只读,可读写… 下面三种情况,会生成一个临时变量存放结果,这个临时变量具有常性(只读性):
这个临时变量可以引用绑定,当被绑定后,就不会被销毁(生命周期) 但是,我们在绑定这个临时变量时要注意权限放大错误,如下:
int main() {
int a = 1;
int b = 2;
int &c = a + b;
return 0;
}
出现权限放大错误,因为a + b
返回时,会产生一个具有只读性的临时变量,但是企图用int
类型来接受它,放大了权限,导致错误。权限可以缩小,但是不能放大。
类似的还有:
int main() {
double a = 3.14;
int &b = int(a);
return 0;
}
int ADD(int a, int b) {
return a + b;
}
int main() {
int& c = ADD(1, 2);
return 0;
}
const int a = 10;
int& ra = a;
在C++中,const
引用(常量引用)是一种特殊的引用类型,它允许你通过引用的方式访问一个对象,但不能通过该引用修改对象的值。修改引用对象,被引用对象也被修改
const
引用通过在引用声明前加上 const
关键字来定义。它的语法如下:
const T& ref = obj;
T
是类型。ref
是引用的名称。obj
是被引用的对象。示例:
int x = 10;
const int& ref = x; // ref 是 x 的 const 引用
只读性:通过 const
引用,只能读取对象的值,不能修改对象的值。
int x = 10;
const int& ref = x;
std::cout << ref; // 正确:读取值
ref = 20; // 错误:不能通过 const 引用修改值
绑定到临时对象:const
引用可以绑定到临时对象(右值),并且会延长临时对象的生命周期。(因为const也只具有只读性,不会有权限放大的问题)
const int& ref = 42; // 正确:绑定到临时对象
避免拷贝:const
引用可以避免不必要的对象拷贝,特别是在函数参数传递时。
void printValue(const std::string& str) {
std::cout << str;
}
int main() {
std::string s = "Hello, World!";
printValue(s); // 避免拷贝
return 0;
}
const
引用常用于函数参数传递,特别是当函数不需要修改参数的值时。这种方式可以避免不必要的拷贝,同时保证参数的值不会被意外修改。
示例:
void printValue(const int& value) {
std::cout << value;
}
int main() {
int x = 10;
printValue(x); // 传递 x 的 const 引用
return 0;
}
const
引用可以绑定到临时对象(右值),并且会延长临时对象的生命周期。
示例:
const std::string& getString() {
return "Hello, World!"; // 返回临时对象的 const 引用
}
int main() {
const std::string& ref = getString(); // 延长临时对象的生命周期
std::cout << ref; // 输出 "Hello, World!"
return 0;
}
const
引用可以防止权限放大错误,即防止将只读对象转换为可读写对象。
示例:
int getValue() {
return 42; // 返回临时对象
}
int main() {
const int& ref = getValue(); // 正确:绑定到临时对象的 const 引用
// int& ref = getValue(); // 错误:权限放大错误
return 0;
}
特性 | const 引用 | 普通引用 |
---|---|---|
是否可修改对象 | 不可修改 | 可修改 |
能否绑定到临时对象 | 可以 | 不可以 |
权限 | 只读 | 可读写 |
常见用途 | 函数参数传递、绑定临时对象 | 需要修改对象时使用 |
sizeof
的含义不同,引用结果大小为引用类型的大小,指针始终为地址空间所占字节个数宏函数(通常也称为宏定义)是在编程中一种预处理指令,它允许你定义一个标识符来代表一段代码片段。在编译之前,预处理器会将源文件中所有使用该标识符的地方替换为对应的代码片段。
#define 宏名(参数列表) 替换文本
注意:
1,替换文本后面不接;
2,替换文本中要多用括号来体现优先级,不然容易出现替换后的优先级问题
示例:
#define ADD(x, y) ((x) - (y))
内联函数(Inline Function) 是C++中的一种函数优化机制,通过在函数定义前加上 inline
关键字,建议编译器将函数调用处直接替换为函数体代码,以减少函数调用的开销。
inline
只是建议,编译器有权决定是否内联,通常适用于简单、频繁调用的函数。当函数过于复杂时,编译器依旧会当做普通的函数来运行,开辟栈帧。示例:
#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
是 C++11 引入的关键字,用于表示空指针。它解决了 C 语言中 NULL
的一些问题,提供了更安全、更清晰的空指针表示方式。
特性 | nullptr (C++11) | NULL (C/C++) |
---|---|---|
类型 | 是 std::nullptr_t 类型,可以隐式转换为任意指针类型 | 通常是 0 或 (void*)0,是一个宏定义 |
类型安全 | 类型安全,不会与整数类型混淆 | 可能被误认为是整数类型(如 int) |
重载函数解析 | 能正确区分指针和整数重载 | 可能导致重载函数解析错误 |
代码清晰性 | 明确表示空指针,语义清晰 | 语义不够明确,可能被误解为整数 0 |
类型安全问题
在 C++ 中,NULL
通常被定义为 0
或 (void*)0
,这可能导致类型混淆。例如:
void foo(int);
void foo(char*);
foo(NULL); // 调用 foo(int),而不是 foo(char*)
使用 nullptr
可以避免这种问题:
foo(nullptr); // 明确调用 foo(char*)
重载函数解析
NULL
可能被当作整数 0
,导致调用错误的重载函数。nullptr
明确表示指针类型,能正确匹配指针重载。代码清晰性
nullptr
明确表示空指针,提高了代码的可读性和语义清晰性。C++ 类型系统的改进
nullptr
是 std::nullptr_t
类型,可以隐式转换为任意指针类型,但不能转换为整数类型,增强了类型检查。示例:
#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;
}