第二章:C++基础:从C到C++的进化
说实话,我当年从C转向C++的时候,心里是有点抵触的。总觉得C已经够用了,干嘛要学那些花里胡哨的东西?直到我在一个大型项目中,被一堆函数指针和内存管理搞得焦头烂额,才真正体会到C++带来的改变。这一章,我们就聊聊C++到底在C的基础上进化了什么。
2.1 引用与指针的区别
很多初学者会问:引用和指针到底有啥区别?说白了,引用就是一个“自动解引用的指针”。但实际用起来,差别可大了去了。
核心区别一览
| 特性 | 指针 | 引用 |
|---|---|---|
| 是否可为空 | 可以(NULL) | 必须初始化,不能为空 |
| 能否重新绑定 | 可以 | 不能 |
| 内存占用 | 通常8字节(64位) | 不占额外空间(别名) |
| 语法糖 | 需要 * 和 & | 像普通变量一样使用 |
我个人习惯在函数参数传递时,优先使用引用。为什么呢?你想想看,指针可能为空,每次用之前都得检查一下,多麻烦。引用就没这个烦恼。
// 指针版本:需要检查空指针
void process(int* p) {
if (p == nullptr) return; // 烦不烦?
*p = 42;
}
// 引用版本:干净利落
void process(int& r) {
r = 42; // 直接干,不用操心
}
我的经验:在实现拷贝构造函数和赋值运算符时,参数一定要用 const 引用。我在项目中见过有人用指针传参,结果忘了检查空指针,线上崩溃了。嗯,那场面...挺尴尬的。
2.2 const的深度解析
const 这个关键字,看着简单,用起来门道不少。我见过很多代码,const 用得乱七八糟的。其实只要记住一个原则:const 修饰的是它左边的东西。
const int* p; // p 指向的值不能改
int* const p; // p 本身不能改(指向不能变)
const int* const p; // 两者都不能改
为什么会这样?因为 C++ 的声明语法是“从右向左读”的。嗯,这里要注意,const 出现在类型左边和右边,效果是一样的:
const int a = 10; // 等价于
int const a = 10; // 一样的效果
避坑指南:我曾经在一个项目中,把 const 成员函数写成了非 const,结果导致整个模块的 const 正确性全乱了。记住:const 成员函数不能修改成员变量(除非变量被 mutable 修饰)。
const 还有一个妙用:修饰函数返回值。比如返回一个内部数组的指针,用 const 可以防止外部修改:
class Buffer {
char data[1024];
public:
const char* getData() const { return data; }
};
这样调用方就只能读,不能写。安全多了,对吧?
2.3 函数重载与默认参数
函数重载,说白了就是“同名不同参”。C 语言不支持这个,但 C++ 可以。编译器会根据参数类型和个数,自动匹配最合适的版本。
void print(int i) { cout << "整数: " << i << endl; }
void print(double d) { cout << "浮点数: " << d << endl; }
void print(const char* s) { cout << "字符串: " << s << endl; }
调用的时候,编译器会自动选择:
print(42); // 调用 int 版本
print(3.14); // 调用 double 版本
print("hello"); // 调用 const char* 版本
注意:重载不能只看返回值类型。比如下面这样是不行的:
int foo();
double foo(); // 编译错误!
因为调用时无法区分。
默认参数就更有意思了。它允许你在声明函数时给参数一个默认值:
void connect(const char* host, int port = 8080) {
// 连接服务器
}
connect("localhost"); // 使用默认端口 8080
connect("server.com", 443); // 指定端口 443
我个人建议:默认参数放在声明里,不要放在定义里。否则容易出问题:
// 头文件(声明)
void func(int a, int b = 10);
// 源文件(定义)
void func(int a, int b) { // 这里不要写默认值
// ...
}
我的习惯:默认参数和函数重载可以配合使用。比如一个函数有多个参数需要默认值,用重载可能更清晰。但别滥用,否则代码会变得难以理解。
本章知识体系
下面这张图,是我梳理的本章核心知识点之间的关系:
这张图把本章的三个核心知识点串起来了。你看,引用与指针解决的是“怎么传数据”的问题,const 解决的是“怎么保护数据”的问题,函数重载和默认参数解决的是“怎么让接口更友好”的问题。三者相辅相成,共同构成了 C++ 基础的核心。
总结一下:从 C 到 C++,不是简单的语法升级,而是一种编程思维的转变。引用让传参更安全,const 让接口更严谨,重载和默认参数让代码更灵活。这些特性用好了,代码质量能上一个台阶。
好了,这一章就到这里。记住我上面说的那些坑,写代码的时候多留个心眼。下一章我们聊聊类和对象,那才是 C++ 真正精彩的地方。