C++编程从入门到实践:面向对象与STL核心特性详解
C++作为一门功能强大的编程语言,在系统开发、游戏引擎、高性能计算等领域有着广泛应用。对于已经掌握C语言基础的程序员来说,学习C++不仅是语法上的扩展,更是编程思维从面向过程到面向对象的重大转变。
本文基于北京大学《C++程序设计》课程的核心内容,结合当前C++开发的实际需求,重点讲解C++语言的基础特性和面向对象编程思想。无论你是准备面试C++岗位,还是想要开发更复杂的应用程序,掌握这些基础知识都至关重要。
1. C++核心能力速览
| 能力项 | 说明 |
|---|---|
| 语言类型 | 静态类型、编译型、多范式编程语言 |
| 主要特性 | 面向对象、泛型编程、内存管理、运算符重载 |
| 开发环境 | Visual Studio、CLion、VSCode、GCC/Clang |
| 适用场景 | 系统软件、游戏开发、嵌入式系统、高性能计算 |
| 学习前提 | 建议具备C语言基础和基本算法知识 |
2. 从C到C++的平滑过渡
2.1 C++对C语言的扩展
C++在C语言基础上增加了许多重要特性,这些特性使得编程更加安全和高效:
// 引用:C++的重要扩展 #include <iostream> using namespace std; void swap(int &a, int &b) { int temp = a; a = b; b = temp; } int main() { int x = 5, y = 10; swap(x, y); // 直接传递变量,无需取地址 cout << "x=" << x << ", y=" << y << endl; return 0; }引用(Reference)是C++中非常重要的概念,它提供了指针的替代方案,使代码更加简洁安全。与指针不同,引用必须在声明时初始化,且不能改变指向的对象。
2.2 const关键字和常量定义
// const关键字的使用 const int MAX_SIZE = 100; // 常量定义 const double PI = 3.14159; void printArray(const int arr[], int size) { // arr被声明为const,不能在函数内修改 for(int i = 0; i < size; i++) { cout << arr[i] << " "; } cout << endl; }const关键字不仅用于定义常量,还能保护函数参数不被意外修改,提高代码的健壮性。
3. 面向对象编程基础
3.1 类和对象的概念
类是C++面向对象编程的核心,它将数据和对数据的操作封装在一起:
// 简单的类定义示例 class Student { private: string name; int age; double score; public: // 构造函数 Student(string n, int a, double s) : name(n), age(a), score(s) {} // 成员函数 void displayInfo() { cout << "姓名:" << name << endl; cout << "年龄:" << age << endl; cout << "成绩:" << score << endl; } // 设置成绩 void setScore(double s) { if(s >= 0 && s <= 100) { score = s; } } // 获取成绩 double getScore() const { return score; } }; // 使用示例 int main() { Student stu("张三", 20, 85.5); stu.displayInfo(); stu.setScore(90.0); cout << "新成绩:" << stu.getScore() << endl; return 0; }3.2 构造函数和析构函数
构造函数在对象创建时自动调用,析构函数在对象销毁时自动调用:
class String { private: char *str; int length; public: // 默认构造函数 String() : str(nullptr), length(0) { cout << "默认构造函数被调用" << endl; } // 参数化构造函数 String(const char *s) { length = strlen(s); str = new char[length + 1]; strcpy(str, s); cout << "参数化构造函数被调用" << endl; } // 拷贝构造函数 String(const String &other) { length = other.length; str = new char[length + 1]; strcpy(str, other.str); cout << "拷贝构造函数被调用" << endl; } // 析构函数 ~String() { delete[] str; cout << "析构函数被调用" << endl; } void print() const { if(str) cout << str << endl; } };4. 运算符重载
运算符重载让自定义类型能够像内置类型一样使用运算符:
class Complex { private: double real; double imag; public: Complex(double r = 0, double i = 0) : real(r), imag(i) {} // 重载+运算符 Complex operator+(const Complex &other) const { return Complex(real + other.real, imag + other.imag); } // 重载-运算符 Complex operator-(const Complex &other) const { return Complex(real - other.real, imag - other.imag); } // 重载输出运算符(友元函数) friend ostream& operator<<(ostream &os, const Complex &c) { os << c.real << " + " << c.imag << "i"; return os; } }; // 使用示例 int main() { Complex c1(3, 4); Complex c2(1, 2); Complex c3 = c1 + c2; cout << c1 << " + " << c2 << " = " << c3 << endl; return 0; }5. 继承与多态
5.1 继承的基本概念
继承是面向对象的重要特性,允许创建层次化的类结构:
// 基类 class Shape { protected: string color; public: Shape(string c) : color(c) {} virtual double area() const = 0; // 纯虚函数 virtual void draw() const { cout << "绘制" << color << "的图形" << endl; } }; // 派生类 class Circle : public Shape { private: double radius; public: Circle(string c, double r) : Shape(c), radius(r) {} double area() const override { return 3.14159 * radius * radius; } void draw() const override { cout << "绘制" << color << "的圆形,半径:" << radius << endl; } }; class Rectangle : public Shape { private: double width, height; public: Rectangle(string c, double w, double h) : Shape(c), width(w), height(h) {} double area() const override { return width * height; } void draw() const override { cout << "绘制" << color << "的矩形,尺寸:" << width << "x" << height << endl; } };5.2 多态的实现
多态允许使用基类指针调用派生类的方法:
void demonstratePolymorphism() { Shape *shapes[3]; shapes[0] = new Circle("红色", 5.0); shapes[1] = new Rectangle("蓝色", 4.0, 6.0); shapes[2] = new Circle("绿色", 3.0); for(int i = 0; i < 3; i++) { shapes[i]->draw(); cout << "面积:" << shapes[i]->area() << endl; cout << "--------" << endl; } // 释放内存 for(int i = 0; i < 3; i++) { delete shapes[i]; } }6. 模板编程
模板是C++泛型编程的基础,允许编写与数据类型无关的代码:
6.1 函数模板
// 函数模板示例 template<typename T> T max(T a, T b) { return (a > b) ? a : b; } template<typename T> void swap(T &a, T &b) { T temp = a; a = b; b = temp; } // 使用示例 void templateDemo() { int a = 5, b = 10; cout << "较大值:" << max(a, b) << endl; double x = 3.14, y = 2.71; swap(x, y); cout << "交换后:x=" << x << ", y=" << y << endl; }6.2 类模板
// 类模板示例:简单的栈实现 template<typename T, int MAX_SIZE = 100> class Stack { private: T data[MAX_SIZE]; int topIndex; public: Stack() : topIndex(-1) {} void push(const T &item) { if(topIndex < MAX_SIZE - 1) { data[++topIndex] = item; } } T pop() { if(topIndex >= 0) { return data[topIndex--]; } return T(); // 返回默认值 } bool isEmpty() const { return topIndex == -1; } int size() const { return topIndex + 1; } }; // 使用示例 void stackDemo() { Stack<int> intStack; intStack.push(1); intStack.push(2); intStack.push(3); while(!intStack.isEmpty()) { cout << intStack.pop() << " "; } cout << endl; }7. 标准模板库(STL)基础
STL是C++标准库的重要组成部分,提供了丰富的容器和算法:
7.1 常用容器
#include <vector> #include <list> #include <map> #include <algorithm> void stlContainerDemo() { // vector示例 vector<int> vec = {1, 2, 3, 4, 5}; vec.push_back(6); cout << "vector元素:"; for(auto it = vec.begin(); it != vec.end(); ++it) { cout << *it << " "; } cout << endl; // list示例 list<string> names = {"Alice", "Bob", "Charlie"}; names.push_back("David"); cout << "list元素:"; for(const auto &name : names) { cout << name << " "; } cout << endl; // map示例 map<string, int> scores; scores["Alice"] = 95; scores["Bob"] = 87; scores["Charlie"] = 92; cout << "map元素:" << endl; for(const auto &pair : scores) { cout << pair.first << ": " << pair.second << endl; } }7.2 算法使用
void stlAlgorithmDemo() { vector<int> numbers = {3, 1, 4, 1, 5, 9, 2, 6}; // 排序 sort(numbers.begin(), numbers.end()); cout << "排序后:"; for(int num : numbers) { cout << num << " "; } cout << endl; // 查找 auto it = find(numbers.begin(), numbers.end(), 5); if(it != numbers.end()) { cout << "找到元素5,位置:" << distance(numbers.begin(), it) << endl; } // 反转 reverse(numbers.begin(), numbers.end()); cout << "反转后:"; for(int num : numbers) { cout << num << " "; } cout << endl; }8. 文件操作
C++提供了强大的文件操作功能:
#include <fstream> #include <sstream> void fileOperationDemo() { // 写入文件 ofstream outFile("data.txt"); if(outFile.is_open()) { outFile << "Hello, C++ File IO!" << endl; outFile << "这是第二行内容" << endl; outFile.close(); cout << "文件写入成功" << endl; } // 读取文件 ifstream inFile("data.txt"); string line; if(inFile.is_open()) { cout << "文件内容:" << endl; while(getline(inFile, line)) { cout << line << endl; } inFile.close(); } // 字符串流 stringstream ss; ss << "姓名:李四" << endl; ss << "年龄:25" << endl; ss << "成绩:88.5" << endl; cout << "字符串流内容:" << endl; cout << ss.str(); }9. 异常处理
良好的异常处理机制可以提高程序的健壮性:
class DivisionByZeroException : public exception { public: const char* what() const noexcept override { return "除零错误:除数不能为零"; } }; double safeDivide(double a, double b) { if(b == 0) { throw DivisionByZeroException(); } return a / b; } void exceptionHandlingDemo() { try { double result1 = safeDivide(10, 2); cout << "10 / 2 = " << result1 << endl; double result2 = safeDivide(5, 0); // 会抛出异常 cout << "5 / 0 = " << result2 << endl; } catch(const DivisionByZeroException &e) { cout << "捕获到异常:" << e.what() << endl; } catch(const exception &e) { cout << "捕获到其他异常:" << e.what() << endl; } cout << "程序继续执行..." << endl; }10. 现代C++特性(C++11/14/17)
10.1 自动类型推导
void modernCppDemo() { // auto关键字 auto x = 42; // int auto y = 3.14; // double auto name = "C++"; // const char* vector<int> numbers = {1, 2, 3, 4, 5}; // 范围for循环 cout << "范围for循环:"; for(auto num : numbers) { cout << num << " "; } cout << endl; // lambda表达式 auto square = [](int n) { return n * n; }; cout << "5的平方:" << square(5) << endl; // 使用lambda进行排序 vector<string> words = {"apple", "banana", "cherry", "date"}; sort(words.begin(), words.end(), [](const string &a, const string &b) { return a.length() < b.length(); }); cout << "按长度排序:"; for(const auto &word : words) { cout << word << " "; } cout << endl; }10.2 智能指针
#include <memory> void smartPointerDemo() { // unique_ptr:独占所有权 unique_ptr<int> ptr1 = make_unique<int>(42); cout << "unique_ptr值:" << *ptr1 << endl; // shared_ptr:共享所有权 shared_ptr<string> ptr2 = make_shared<string>("Hello"); shared_ptr<string> ptr3 = ptr2; // 共享所有权 cout << "shared_ptr值:" << *ptr2 << endl; cout << "引用计数:" << ptr2.use_count() << endl; // weak_ptr:不增加引用计数 weak_ptr<string> weakPtr = ptr2; if(auto sharedPtr = weakPtr.lock()) { cout << "weak_ptr获取的值:" << *sharedPtr << endl; } }11. 实战项目:学生管理系统
下面是一个综合运用C++特性的简单学生管理系统:
#include <iostream> #include <vector> #include <memory> #include <algorithm> class Student { private: string name; int id; double score; public: Student(string n, int i, double s) : name(n), id(i), score(s) {} string getName() const { return name; } int getId() const { return id; } double getScore() const { return score; } void setScore(double s) { score = s; } void display() const { cout << "学号:" << id << ",姓名:" << name << ",成绩:" << score << endl; } }; class StudentManager { private: vector<shared_ptr<Student>> students; public: void addStudent(const string &name, int id, double score) { auto student = make_shared<Student>(name, id, score); students.push_back(student); cout << "添加学生成功!" << endl; } void displayAll() const { if(students.empty()) { cout << "暂无学生信息" << endl; return; } cout << "所有学生信息:" << endl; for(const auto &student : students) { student->display(); } } shared_ptr<Student> findStudent(int id) const { auto it = find_if(students.begin(), students.end(), [id](const shared_ptr<Student> &s) { return s->getId() == id; }); if(it != students.end()) { return *it; } return nullptr; } void sortByScore() { sort(students.begin(), students.end(), [](const shared_ptr<Student> &a, const shared_ptr<Student> &b) { return a->getScore() > b->getScore(); }); cout << "按成绩排序完成!" << endl; } }; // 使用示例 void studentSystemDemo() { StudentManager manager; manager.addStudent("张三", 1001, 85.5); manager.addStudent("李四", 1002, 92.0); manager.addStudent("王五", 1003, 78.5); cout << "\n--- 显示所有学生 ---" << endl; manager.displayAll(); cout << "\n--- 查找学号1002的学生 ---" << endl; auto student = manager.findStudent(1002); if(student) { student->display(); } else { cout << "未找到该学生" << endl; } cout << "\n--- 按成绩排序后 ---" << endl; manager.sortByScore(); manager.displayAll(); }12. 常见问题与解决方案
12.1 内存管理问题
问题:内存泄漏
// 错误示例 void memoryLeakDemo() { int *ptr = new int[100]; // 分配内存 // 忘记delete[] ptr; // 内存泄漏! } // 正确做法 void correctMemoryDemo() { // 使用智能指针 auto ptr = make_unique<int[]>(100); // 自动释放内存 }问题:野指针
// 错误示例 void wildPointerDemo() { int *ptr = new int(42); delete ptr; // ptr现在成为野指针 *ptr = 100; // 未定义行为! } // 正确做法 void correctPointerDemo() { auto ptr = make_unique<int>(42); // 不需要手动delete // ptr离开作用域时自动释放 }12.2 编译错误排查
常见编译错误及解决方法:
- 未定义引用错误:检查函数声明和定义是否匹配,链接是否正确
- 模板实例化错误:确保模板参数满足要求
- 类型不匹配:检查函数参数类型和返回值类型
- 头文件包含问题:确保必要的头文件都已包含
13. 开发环境配置建议
13.1 VSCode配置
// .vscode/settings.json { "C_Cpp.default.cppStandard": "c++17", "C_Cpp.default.intelliSenseMode": "gcc-x64", "files.associations": { "*.cpp": "cpp" } }13.2 编译命令示例
# 使用g++编译 g++ -std=c++17 -Wall -Wextra -O2 main.cpp -o program # 使用CMake cmake_minimum_required(VERSION 3.10) project(MyProject) set(CMAKE_CXX_STANDARD 17) add_executable(program main.cpp)14. 学习路径建议
- 基础阶段:掌握C++基本语法、面向对象概念
- 进阶阶段:学习模板、STL、异常处理
- 高级阶段:深入理解现代C++特性、内存模型、多线程
- 实战阶段:参与实际项目开发,阅读优秀开源代码
通过系统学习C++语言基础,你不仅能够编写更复杂的程序,还能更好地理解计算机系统的工作原理。建议在学习过程中多动手实践,从简单程序开始,逐步挑战更复杂的项目。
