首先是 C 到 C++ 的过渡的基础特性
1. C++ 中改进的 C 代码中潜在危险操作
| C 中的问题 | C++ 解法 | 为什么更好 |
|---|---|---|
手动 malloc/free → 内存泄漏 |
RAII + 智能指针 std::unique_ptr<T>, std::shared_ptr<T> |
自动释放,异常安全 |
数组越界、忘记 \0 |
std::vector<T>, std::string |
自动管理大小,支持 size(), push_back() |
| 函数参数传递大结构体(值拷贝开销) | const T& 引用传参 |
零拷贝,语义清晰 |
宏定义(#define MAX 100) |
constexpr int MAX = 100; |
类型安全,作用域可控 |
2. 结构体---类的过渡
| 场景 | C++ 方案 | 对比 C |
|---|---|---|
| 封装数据+操作(如 socket、file handle) | class / struct + 成员函数 | 比 C 的 struct + function pointers 更简洁 |
| 多态(不同设备执行不同操作) | 虚函数(virtual) | 比 C 的 switch(type) 或函数指针表更安全 |
| 泛型(通用容器/算法) | 模板(template) | 比 C 的 void* 宏更类型安全 |
2.0 结构体与封装
c
#include <stdio.h>
// 仅仅是数据的集合
typedef struct {
char name[50];
int age;
} Person;
// 操作数据的函数是独立的
void Person_init(Person* p, const char* name, int age) {
strcpy(p->name, name);
p->age = age;
}
void Person_print(Person* p) {
printf("Name: %s, Age: %d\n", p->name, p->age);
}
// 使用
void c_struct_test() {
Person p; // 数据未初始化,里面是垃圾值
Person_init(&p, "Tom", 25); // 必须记得调用初始化
Person_print(&p);
}
cpp
#include <iostream>
#include <string>
class Person {
private: // 私有成员,外部无法直接乱改
std::string name;
int age;
public:
// 构造函数:创建对象时自动调用,保证初始化
Person(std::string n, int a) : name(n), age(a) {}
// 成员函数:直接操作内部数据
void print() const {
std::cout << "Name: " << name << ", Age: " << age << std::endl;
}
};
// 使用
void cpp_class_test() {
// Person p; // 编译错误!因为没有提供 name 和 age,禁止创建未初始化的对象
Person p("Tom", 25); // 创建即初始化
p.print();
}
2.1 【malloc/free】 vs 【RAll】
- C 的思维:申请内存 --- 使用 --- 释放内存
- C++ 的思维:使用
std::vector或者std::unique_ptr,对象创建时自动申请资源,对象超多作用范围时,析构函数自动释放资源。
2.2 字符串管理
- C的思维:字符串就是以
\0结尾的字符数组,计算长度要 strlen,拼接要strcat,不仅麻烦还容易越界。 - C++的思维:使用
std::string和std::vector。它们会自动管理内存大小,自动扩容,且自带长度记录。
c
// C 字符串拼接
const char* s1 = "Hello";
const char* s2 = " World";
int len = strlen(s1) + strlen(s2) + 1;
char* result = (char*)malloc(len * sizeof(char));
strcpy(result, s1);
strcat(result, s2);
free(result);
cpp
// C++ 字符串拼接
std::string s1 = "Hello";
std::string s2 = " World";
std::string result = s1 + s2;
2.3 动态数组
c
// C
int size = 5;
int* arr = (int*)malloc(size * sizeof(int));
// c++
std::vector<int> arr = {0, 10, 20, 30, 40};
arr.push_back(50);
2.4 智能指针
c
int process_data_c() {
int* ptr = (int*)malloc(sizeof(int));
*ptr = 100;
if (*ptr > 50) {
// 糟糕!如果你这里直接 return,ptr指向的内存就泄露了
// 你必须记得写 free(ptr);
return -1;
}
free(ptr);
return 0;
}
cpp
#include <memory> // 引入智能指针
int process_data_cpp() {
// unique_ptr 独占这个指针的所有权
// make_unique 是 C++14 引入的,比 new 更安全
std::unique_ptr<int> ptr = std::make_unique<int>(100);
if (*ptr > 50) {
// 即使在这里 return
// ptr 是栈上的对象,它的析构函数会被调用
// 析构函数会自动 free 掉它管理的堆内存
return -1;
}
// 函数结束,自动释放
return 0;
}