基于C语言快速了解C++面向程序设计(期末适用)
# C++ 语法学习指南(从 C 语言过渡)
---
> **适用对象:** 已熟练掌握 C 语言,需快速学习 C++ 面向对象编程
> **推荐阅读方式:** 从上到下依次阅读,每个知识点附带 C 语言对比
---
## 目录
1. [C++ 与 C 的基础差异](#一c-与-c-的基础差异)
2. [输入输出流 (iostream)](#二输入输出流-iostream)
3. [命名空间 (namespace)](#三命名空间-namespace)
4. [引用 (Reference)](#四引用-reference)
5. [动态内存分配 (new / delete)](#五动态内存分配-new--delete)
6. [类与对象 (Class & Object)](#六类与对象-class--object)
7. [构造函数 (Constructor)](#七构造函数-constructor)
8. [析构函数 (Destructor)](#八析构函数-destructor)
9. [this 指针](#九this-指针)
10. [const 成员函数](#十const-成员函数)
11. [成员初始化列表](#十一成员初始化列表)
12. [类的组合](#十二类的组合)
13. [string 类与字符数组](#十三string-类与字符数组)
14. [C++ 常用头文件速查](#十四c-常用头文件速查)
---
## 一、C++ 与 C 的基础差异
### 1.1 文件扩展名
| 语言 | 扩展名 |
|------|--------|
| C | `.c` |
| C++ | `.cpp`、`.cc`、`.cxx` |
### 1.2 头文件
| C 语言 | C++ 等价写法 |
|--------|-------------|
| `#include <stdio.h>` | `#include <cstdio>` |
| `#include <string.h>` | `#include <cstring>` |
| `#include <math.h>` | `#include <cmath>` |
| `#include <stdlib.h>` | `#include <cstdlib>` |
```cpp
// C++ 推荐写法(名字前加 c,去掉 .h)
#include <cstdio> // 对应 C 的 <stdio.h>
#include <cstring> // 对应 C 的 <string.h>
#include <cmath> // 对应 C 的 <math.h>
```
### 1.3 bool 类型
C 语言没有内置的 bool 类型(需 `#include <stdbool.h>`),C++ 内置:
```cpp
bool flag = true; // C++ 内置布尔类型
bool isOK = false;
if (flag) {
// 直接使用
}
```
---
## 二、输入输出流 (iostream)
### 2.1 基本用法
这是 C++ 与 C 最明显的区别,用 `cout`/`cin` 替代 `printf`/`scanf`。
```cpp
#include <iostream>
using namespace std;
int main() {
int a;
double b;
char c;
// 输入:cin >> 变量
cin >> a; // 读取整数
cin >> b; // 读取浮点数
cin >> c; // 读取字符
// 输出:cout << 内容
cout << "Hello"; // 输出字符串
cout << a; // 输出变量
cout << "a = " << a << endl; // 链式输出
// endl 相当于换行符 '\n',并刷新缓冲区
return 0;
}
```
### 2.2 与 C 语言对比
| C 语言 | C++ |
|--------|-----|
| `printf("%d", x);` | `cout << x;` |
| `scanf("%d", &x);` | `cin >> x;` |
| `printf("\n");` | `cout << endl;` 或 `cout << '\n';` |
| 需要格式说明符 `%d %f %s` | 自动类型识别,无需格式符 |
### 2.3 读取包含空格的字符串
```cpp
#include <iostream>
using namespace std;
int main() {
char name[21];
// 错误:cin >> 遇到空格就停止
// cin >> name; // 输入 "zhang san" 只能读到 "zhang"
// 正确:使用 cin.getline()
cin.getline(name, 21); // 读取整行(含空格),最多20个字符
cout << name;
return 0;
}
```
### 2.4 cin >> 与 cin.getline() 混用问题(重要!)
```cpp
int main() {
int id;
char name[21];
cin >> id; // 输入 1002,缓冲区留下换行符 '\n'
cin.ignore(); // 吸收掉换行符,否则 getline 会读到空行
cin.getline(name, 21); // 正常读取 "zhang san"
cout << "ID: " << id << endl;
cout << "Name: " << name << endl;
return 0;
}
```
**原理:** `cin >>` 读取后,输入缓冲区会残留一个换行符 `'\n'`。`cin.getline()` 遇到换行符就立即结束,会读到空字符串。所以需要用 `cin.ignore()` 把换行符"吃掉"。
---
## 三、命名空间 (namespace)
### 3.1 概念
命名空间是为了避免**命名冲突**。比如不同库中可能有同名的函数,用命名空间来区分。
```cpp
#include <iostream>
// 不使用命名空间
int main() {
std::cout << "Hello" << std::endl; // 每次都要写 std::
return 0;
}
// 使用命名空间
using namespace std;
int main() {
cout << "Hello" << endl; // 可以省略 std::
return 0;
}
```
### 3.2 三种用法
```cpp
// 方式一:全局引入(最简单,但可能污染命名空间)
using namespace std;
// 方式二:引入特定名称
using std::cout;
using std::endl;
// 方式三:每次使用时加前缀(最安全)
std::cout << "Hello" << std::endl;
```
---
## 四、引用 (Reference)
### 4.1 概念
引用是变量的**别名**,操作引用就是操作原变量。这是 C++ 新增的特性,C 语言中没有。
```cpp
int a = 10;
int &ref = a; // ref 是 a 的引用(别名)
ref = 20; // 修改 ref 就是修改 a
cout << a; // 输出 20
```
### 4.2 与指针的对比
| 特性 | 指针 | 引用 |
|------|------|------|
| 声明 | `int *p = &a;` | `int &ref = a;` |
| 使用 | `*p = 20;` | `ref = 20;`(直接使用) |
| 可空 | 可以为 NULL | 必须初始化,不能为空 |
| 可修改指向 | 可以指向别的变量 | 绑定后不能改变 |
| 取地址 | `p` 本身是地址 | `&ref` 取地址 |
```cpp
void swap(int &x, int &y) { // 引用参数,直接修改原变量
int temp = x;
x = y;
y = temp;
}
int main() {
int a = 1, b = 2;
swap(a, b); // 调用后 a=2, b=1(无需传指针)
return 0;
}
```
### 4.3 常引用 (const reference)
```cpp
void print(const Point &p) { // 不会修改 p,且避免拷贝
cout << p.GetX();
}
```
---
## 五、动态内存分配 (new / delete)
### 5.1 基本用法
C++ 用 `new`/`delete` 替代 C 的 `malloc`/`free`。
| C 语言 | C++ |
|--------|-----|
| `int *p = malloc(sizeof(int));` | `int *p = new int;` |
| `*p = 5;` | `int *p = new int(5);` |
| `free(p);` | `delete p;` |
| `int *arr = malloc(10 * sizeof(int));` | `int *arr = new int[10];` |
| `free(arr);` | `delete[] arr;` |
```cpp
// 分配单个变量并初始化
int *p = new int(5); // 分配一个 int,值为 5
cout << *p; // 输出 5
delete p; // 释放内存
// 分配数组
int *arr = new int[10]; // 分配 10 个 int 的数组
delete[] arr; // 释放数组(注意方括号)
```
### 5.2 关键区别
| | malloc/free | new/delete |
|------|-------------|------------|
| 本质 | 函数 | 运算符 |
| 构造函数 | 不调用 | **自动调用构造函数** |
| 析构函数 | 不调用 | **自动调用析构函数** |
| 类型安全 | 需强转 `(int*)` | 自动返回正确类型指针 |
---
## 六、类与对象 (Class & Object)
### 6.1 基本概念
类是 C++ 面向对象编程的核心。可以把类理解为 C 语言中 `struct` 的升级版。
| 概念 | 类比 C 语言 |
|------|------------|
| 类 (Class) | `struct` 的增强版,包含数据 + 函数 |
| 对象 (Object) | 结构体变量 |
| 成员变量 | 结构体字段 |
| 成员函数 | 操作该结构体的函数 |
### 6.2 类的定义
```cpp
class Student {
public: // 公有成员(外部可访问)
// 成员函数声明
void Set(int id, char name[], char sex, int age);
void Output();
private: // 私有成员(只能在类内部访问)
// 成员变量
int ID;
char name[21];
char sex;
int age;
};
```
### 6.3 访问权限
| 关键字 | 访问范围 | 默认(class) | 默认(struct) |
|--------|----------|--------------|----------------|
| `public` | 任何地方都能访问 | - | struct 默认 |
| `private` | 只有类内部能访问 | class 默认 | - |
| `protected` | 类内部和子类能访问 | - | - |
```cpp
class A {
int a; // 默认 private
};
struct B {
int b; // 默认 public
};
```
### 6.4 成员函数的类外定义
```cpp
class Point {
public:
void Set(double xx, double yy); // 类内声明
double GetX() { return x; } // 类内直接定义(内联)
private:
double x, y;
};
// 类外定义:需要 类名:: 前缀
void Point::Set(double xx, double yy) {
x = xx;
y = yy;
}
```
**语法格式:** `返回类型 类名::函数名(参数列表) { 函数体 }`
### 6.5 创建和使用对象
```cpp
int main() {
Student s; // 创建对象(类似 C 的 struct Student s;)
s.Set(1001, "张三", 'M', 20); // 调用成员函数(用 . 运算符)
s.Output();
// 动态创建对象
Student *ps = new Student;
ps->Set(1002, "李四", 'F', 19); // 指针用 -> 运算符
ps->Output();
delete ps;
return 0;
}
```
---
## 七、构造函数 (Constructor)
### 7.1 概念
构造函数是**创建对象时自动调用**的特殊函数,用于初始化对象。C 语言中需要手动写 `init_xxx()` 函数,C++ 自动完成。
### 7.2 特点
| 特点 | 说明 |
|------|------|
| 函数名 | 必须与**类名完全相同** |
| 返回值 | **没有返回值**(不写 void) |
| 调用时机 | 创建对象时**自动调用** |
| 重载 | **可以重载**(多个构造函数,参数不同) |
### 7.3 默认构造函数
```cpp
class Point {
public:
Point() { // 无参构造函数(默认构造函数)
x = 0;
y = 0;
}
private:
double x, y;
};
```
**重要规则:** 如果类中定义了**任何一个构造函数**,编译器就不再自动生成默认构造函数。
```cpp
class Point {
public:
Point(double xx, double yy) { x = xx; y = yy; } // 定义了有参构造函数
// 编译器不再生成默认构造函数 Point()
private:
double x, y;
};
Point p1; // 错误!没有默认构造函数
Point p2(1, 2); // 正确
```
### 7.4 带默认参数的构造函数
```cpp
class Point {
public:
// 一个构造函数,通过默认参数实现"无参"和"有参"两种效果
Point(double xx = 0, double yy = 0) : x(xx), y(yy) {}
private:
double x, y;
};
Point p1; // 调用 Point(0, 0)
Point p2(1, 2); // 调用 Point(1, 2)
Point p3(5); // 调用 Point(5, 0),只传一个参数
```
### 7.5 构造函数重载
```cpp
class Fraction {
public:
Fraction() : num(0), den(1) {} // 无参:分子0,分母1
Fraction(int n) : num(n), den(1) {} // 单参:分子n,分母1
Fraction(int n, int d) { // 双参:分子n,分母d
if (d == 0) d = 1;
num = n;
den = d;
}
private:
int num, den;
};
Fraction f1; // 调用 Fraction()
Fraction f2(2); // 调用 Fraction(int)
Fraction f3(-3, 4); // 调用 Fraction(int, int)
```
---
## 八、析构函数 (Destructor)
### 8.1 概念
析构函数是**对象销毁时自动调用**的特殊函数,用于释放资源。
### 8.2 特点
| 特点 | 说明 |
|------|------|
| 函数名 | `~类名`(类名前加波浪号) |
| 返回值 | 没有返回值 |
| 参数 | 没有参数(不能重载) |
| 数量 | 每个类只有一个 |
| 调用时机 | 对象生命周期结束时自动调用 |
### 8.3 示例
```cpp
class MyClass {
public:
MyClass() {
data = new int[100]; // 构造函数分配资源
}
~MyClass() {
delete[] data; // 析构函数释放资源
}
private:
int *data;
};
```
---
## 九、this 指针
### 9.1 概念
每个对象都有一个隐含的 `this` 指针,指向**对象自身**。
```cpp
class Point {
public:
void Set(double x, double y) {
this->x = x; // this->x 是成员变量
this->y = y; // 右边的 x, y 是参数
}
private:
double x, y;
};
```
---
## 十、const 成员函数
### 10.1 概念
在函数声明后加 `const`,表示该函数**不会修改对象**的任何成员变量。
```cpp
class Point {
public:
double GetX() const { return x; } // const 成员函数
double GetY() const { return y; }
void Output() const { // 输出不修改对象
cout << "(" << x << "," << y << ")" << endl;
}
void Set(double xx, double yy) { // 修改对象,不能加 const
x = xx;
y = yy;
}
private:
double x, y;
};
```
### 10.2 规则
- const 成员函数内部不能修改成员变量
- const 成员函数只能调用其他 const 成员函数
- const 对象只能调用 const 成员函数
---
## 十一、成员初始化列表
### 11.1 概念
在构造函数体执行之前,用初始化列表直接初始化成员变量。
```cpp
// 方式一:构造函数体内赋值(先默认初始化,再赋值)
Point::Point(double xx, double yy) {
x = xx; // 赋值,不是初始化
y = yy;
}
// 方式二:初始化列表(直接初始化,更高效)
Point::Point(double xx, double yy) : x(xx), y(yy) {
// 构造函数体(可以为空,或做额外操作)
}
```
### 11.2 初始化顺序
成员初始化的顺序**取决于类中声明的顺序**,与初始化列表中的书写顺序无关。
```cpp
class Test {
int x, y, z; // 声明顺序:x → y → z
public:
Test() : z(1), y(2), x(3) {} // 实际初始化顺序仍是 x → y → z
};
```
---
## 十二、类的组合
### 12.1 概念
一个类可以包含另一个类的对象作为数据成员。
```cpp
class Point {
public:
Point(double xx = 0, double yy = 0) : x(xx), y(yy) {}
double GetX() const { return x; }
double GetY() const { return y; }
private:
double x, y;
};
class Rectangle {
public:
Rectangle(Point &p1, Point &p2) : ltp(p1), rbp(p2) {}
double GetLength() const { return rbp.GetX() - ltp.GetX(); }
double GetWidth() const { return rbp.GetY() - ltp.GetY(); }
double GetArea() const { return GetLength() * GetWidth(); }
private:
Point ltp; // 左上角点(Point 对象)
Point rbp; // 右下角点(Point 对象)
};
```
---
## 十三、string 类与字符数组
### 13.1 C 风格字符串(字符数组)
沿用 C 语言的写法,使用 `cstring` 头文件。
```cpp
#include <cstring>
char name[21];
char src[] = "Hello";
strcpy(name, src); // 复制字符串
int len = strlen(name); // 获取长度
int cmp = strcmp(name, "Hello"); // 比较字符串
```
### 13.2 C++ string 类
C++ 提供了更安全、更方便的 `string` 类。
```cpp
#include <string>
using namespace std;
string name;
string greeting = "Hello";
name = "zhang san"; // 直接赋值(无需 strcpy)
name = greeting + " World"; // 字符串拼接(用 + 号)
int len = name.length(); // 获取长度
bool eq = (name == "test"); // 直接比较(用 ==)
```
### 13.3 对比
| 操作 | C 风格 (char[]) | C++ string |
|------|----------------|------------|
| 赋值 | `strcpy(a, b);` | `a = b;` |
| 拼接 | `strcat(a, b);` | `a = a + b;` |
| 比较 | `strcmp(a, b) == 0` | `a == b` |
| 长度 | `strlen(a)` | `a.length()` |
| 头文件 | `<cstring>` | `<string>` |
---
## 十四、C++ 常用头文件速查
| 头文件 | 用途 |
|--------|------|
| `<iostream>` | 输入输出流(cin, cout, endl) |
| `<cstring>` | C 风格字符串函数(strcpy, strlen) |
| `<string>` | C++ string 类 |
| `<cmath>` | 数学函数(sqrt, pow, abs, sin, cos) |
| `<cstdlib>` | 通用工具(NULL, atoi, rand, srand) |
| `<cstdio>` | C 标准 I/O(printf, scanf, FILE) |
---
