C++ 学习指南:核心概念与实践应用
C++ 是一种功能强大且广泛应用的编程语言,尤其适合系统开发、游戏引擎、高性能计算等领域。下面将从核心语法到高级特性,结合实际案例进行讲解。
1. C++ 基础语法与核心概念
C++ 是一种静态类型、编译式语言,支持面向过程、面向对象和泛型编程范式。
基础语法示例:
cpp
#include <iostream> // 输入输出流库
int main() {
// 变量声明与初始化
int num = 42;
double pi = 3.14;
std::string name = "Doubao"; // C++11 标准引入的字符串类
// 条件语句
if (num > 10) {
std::cout << "Number is greater than 10." << std::endl;
}
// 循环语句
for (int i = 0; i < 5; i++) {
std::cout << "Iteration: " << i << std::endl;
}
return 0;
}
2. 面向对象编程(OOP)
C++ 的核心优势之一是支持面向对象编程,包括类、继承、多态等特性。
类与对象示例:
cpp
class Shape {
protected:
std::string name;
public:
// 构造函数
Shape(const std::string& n) : name(n) {}
// 虚函数(用于多态)
virtual double area() const = 0; // 纯虚函数,使 Shape 成为抽象类
// 普通成员函数
void printName() const {
std::cout << "Shape: " << name << std::endl;
}
};
// 派生类:圆形
class Circle : public Shape {
private:
double radius;
public:
Circle(double r) : Shape("Circle"), radius(r) {}
// 实现基类的纯虚函数
double area() const override {
return 3.14 * radius * radius;
}
};
// 派生类:矩形
class Rectangle : public Shape {
private:
double width, height;
public:
Rectangle(double w, double h) : Shape("Rectangle"), width(w), height(h) {}
double area() const override {
return width * height;
}
};
3. 多态(Polymorphism)
多态允许通过基类指针或引用调用派生类的方法,实现运行时绑定。
多态示例:
cpp
void printArea(const Shape& shape) {
shape.printName();
std::cout << "Area: " << shape.area() << std::endl; // 动态绑定到派生类的 area()
}
int main() {
Circle circle(5.0);
Rectangle rect(4.0, 6.0);
printArea(circle); // 输出:Circle, Area: 78.5
printArea(rect); // 输出:Rectangle, Area: 24.0
return 0;
}
4. 工厂模式(Factory Pattern)
工厂模式是一种创建对象的设计模式,将对象的创建逻辑封装在一个工厂类中。
简单工厂示例:
cpp
class ShapeFactory {
public:
static Shape* createShape(const std::string& type) {
if (type == "circle") {
return new Circle(5.0);
} else if (type == "rectangle") {
return new Rectangle(4.0, 6.0);
}
return nullptr; // 无效类型返回 nullptr
}
};
// 使用工厂创建对象
int main() {
Shape* circle = ShapeFactory::createShape("circle");
Shape* rect = ShapeFactory::createShape("rectangle");
if (circle) printArea(*circle);
if (rect) printArea(*rect);
delete circle; // 记得释放动态分配的内存
delete rect;
return 0;
}
5. static
和 const
的用法
static
关键字:
- 静态变量:在类中声明的静态变量为所有对象共享,类外初始化。
- 静态函数:不依赖于对象,只能访问静态成员。
cpp
class Counter {
private:
static int count; // 静态成员变量声明
public:
static int getCount() { // 静态成员函数
return count;
}
void increment() {
count++; // 所有对象共享 count
}
};
// 静态成员变量必须在类外初始化
int Counter::count = 0;
const
关键字:
- 常量变量:值不可修改。
- 常量成员函数:不修改对象状态。
- 常量对象:只能调用常量成员函数。
cpp
class Example {
private:
const int value; // 常量成员变量
int data;
public:
Example(int v, int d) : value(v), data(d) {} // 必须在初始化列表中初始化常量成员
// 常量成员函数(不修改对象状态)
int getData() const {
return data;
}
// 非常量成员函数
void setData(int d) {
data = d;
}
};
// 常量对象只能调用常量成员函数
const Example obj(10, 20);
obj.getData(); // 合法
// obj.setData(30); // 非法:常量对象不能调用非常量函数
1. 对象构造函数详解
C++ 提供了多种构造函数类型,用于对象的初始化。
示例代码:
cpp
class Point {
private:
int x, y;
public:
// 默认构造函数
Point() : x(0), y(0) {}
// 带参数的构造函数
Point(int xVal, int yVal) : x(xVal), y(yVal) {}
// 拷贝构造函数
Point(const Point& other) : x(other.x), y(other.y) {
std::cout << "Copy constructor called" << std::endl;
}
// 移动构造函数(C++11)
Point(Point&& other) noexcept : x(other.x), y(other.y) {
other.x = 0;
other.y = 0;
std::cout << "Move constructor called" << std::endl;
}
// 拷贝赋值运算符
Point& operator=(const Point& other) {
if (this != &other) {
x = other.x;
y = other.y;
}
std::cout << "Copy assignment called" << std::endl;
return *this;
}
// 移动赋值运算符(C++11)
Point& operator=(Point&& other) noexcept {
if (this != &other) {
x = other.x;
y = other.y;
other.x = 0;
other.y = 0;
}
std::cout << "Move assignment called" << std::endl;
return *this;
}
// 析构函数
~Point() {
// 清理资源(如动态内存、文件句柄等)
}
};
// 使用示例
int main() {
Point p1; // 默认构造
Point p2(3, 4); // 带参构造
Point p3 = p2; // 拷贝构造
p1 = p3; // 拷贝赋值
Point p4 = std::move(p1); // 移动构造
p2 = std::move(p3); // 移动赋值
return 0;
}
2. Lambda 表达式(C++11 起)
Lambda 表达式是一种匿名函数对象,用于创建临时函数。
基本语法:
cpp
[capture list](parameter list) -> return type { function body }
示例代码:
cpp
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
// 1. 无捕获,无参数,返回值自动推导
auto greet = [] { std::cout << "Hello, Lambda!" << std::endl; };
greet(); // 输出: Hello, Lambda!
// 2. 捕获外部变量 by value
int x = 10;
auto add_x = [x](int a) { return a + x; };
std::cout << add_x(5) << std::endl; // 输出: 15
// 3. 捕获外部变量 by reference
auto increment = [&x] { x++; };
increment();
std::cout << x << std::endl; // 输出: 11
// 4. 通用捕获(C++14)
auto y = 20;
auto capture_all = [=, &y](int a) { return a + x + y; };
std::cout << capture_all(5) << std::endl; // 输出: 36
// 5. 在算法中使用 lambda
std::vector<int> nums = {1, 2, 3, 4, 5};
std::for_each(nums.begin(), nums.end(), [](int num) {
std::cout << num * 2 << " ";
}); // 输出: 2 4 6 8 10
// 6. 带 mutable 的 lambda
auto modify_captured = [x]() mutable { x++; std::cout << x << std::endl; };
modify_captured(); // 输出: 11(修改的是副本)
std::cout << x << std::endl; // 输出: 10(原 x 未改变)
return 0;
}
3. 智能指针(C++11 起)
智能指针自动管理内存,避免内存泄漏。
示例代码:
cpp
#include <memory>
class Resource {
public:
Resource() { std::cout << "Resource acquired" << std::endl; }
~Resource() { std::cout << "Resource released" << std::endl; }
void use() { std::cout << "Resource in use" << std::endl; }
};
int main() {
// 1. unique_ptr:独占所有权
std::unique_ptr<Resource> res1 = std::make_unique<Resource>();
res1->use();
// std::unique_ptr<Resource> res2 = res1; // 错误:不能拷贝
std::unique_ptr<Resource> res2 = std::move(res1); // 正确:只能移动
// 2. shared_ptr:共享所有权(引用计数)
std::shared_ptr<Resource> res3 = std::make_shared<Resource>();
{
std::shared_ptr<Resource> res4 = res3;
std::cout << "Use count: " << res3.use_count() << std::endl; // 输出: 2
} // res4 析构,引用计数减1
std::cout << "Use count: " << res3.use_count() << std::endl; // 输出: 1
// 3. weak_ptr:弱引用,不增加引用计数
std::shared_ptr<int> shared = std::make_shared<int>(42);
std::weak_ptr<int> weak = shared;
std::cout << "Weak use count: " << weak.use_count() << std::endl; // 输出: 1
if (auto locked = weak.lock()) { // 检查对象是否还存在
std::cout << *locked << std::endl; // 输出: 42
}
return 0;
} // res2、res3、shared 析构,资源释放
4. 模板(Templates)
模板允许创建通用的函数和类,支持泛型编程。
函数模板示例:
cpp
// 交换任意类型的两个值
template <typename T>
void swap(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}
// 使用示例
int x = 5, y = 10;
swap(x, y); // 自动推导 T 为 int
double a = 3.14, b = 2.71;
swap(a, b); // 自动推导 T 为 double
类模板示例:
cpp
// 通用的 Pair 类
template <typename T1, typename T2>
class Pair {
private:
T1 first;
T2 second;
public:
Pair(const T1& a, const T2& b) : first(a), second(b) {}
T1 getFirst() const { return first; }
T2 getSecond() const { return second; }
};
// 使用示例
Pair<int, std::string> p(42, "Doubao");
std::cout << p.getFirst() << ", " << p.getSecond() << std::endl;
5. 右值引用与移动语义(C++11 起)
右值引用允许捕获临时对象(右值),实现资源的高效转移。
示例代码:
cpp
#include <iostream>
#include <vector>
class BigArray {
private:
int* data;
size_t size;
public:
// 构造函数
BigArray(size_t s) : size(s), data(new int[s]) {
std::cout << "Constructor: Allocated " << size << " elements" << std::endl;
}
// 拷贝构造函数
BigArray(const BigArray& other) : size(other.size), data(new int[other.size]) {
std::cout << "Copy Constructor: Allocated and copied " << size << " elements" << std::endl;
for (size_t i = 0; i < size; ++i) {
data[i] = other.data[i];
}
}
// 移动构造函数
BigArray(BigArray&& other) noexcept : data(other.data), size(other.size) {
std::cout << "Move Constructor: Transferred ownership of " << size << " elements" << std::endl;
other.data = nullptr; // 防止 other 析构时删除内存
other.size = 0;
}
// 析构函数
~BigArray() {
delete[] data;
}
};
// 使用示例
BigArray createArray(size_t size) {
return BigArray(size); // 返回临时对象(右值)
}
int main() {
// 拷贝构造(效率低)
BigArray arr1(1000);
BigArray arr2(arr1); // 调用拷贝构造函数
// 移动构造(高效)
BigArray arr3 = createArray(1000); // 调用移动构造函数
return 0;
}
6. 现代 C++ 特性(C++14/17/20)
-
C++14 特性:
cpp
// 泛型 lambda(C++14) auto add = [](auto a, auto b) { return a + b; }; std::cout << add(3, 4) << std::endl; // 输出: 7 std::cout << add(3.14, 2.71) << std::endl; // 输出: 5.85 // 返回类型推导(C++14) auto calculate() { return 3.14 * 2; }
-
C++17 特性:
cpp
// 结构化绑定(Structured Binding) std::pair<int, std::string> getPair() { return {42, "Doubao"}; } auto [num, str] = getPair(); // 直接解包 pair/tuple // if constexpr(编译时条件判断) template <typename T> auto getValue(T t) { if constexpr (std::is_integral_v<T>) { return t * 2; } else { return t; } }
-
C++20 特性:
cpp
// 概念(Concepts) template <typename T> requires std::integral<T> T add(T a, T b) { return a + b; } // 范围(Ranges) std::vector<int> nums = {1, 2, 3, 4, 5}; auto squared = nums | std::views::transform([](int x) { return x * x; });
7. 异常处理
cpp
class DivideByZeroException : public std::exception {
public:
const char* what() const noexcept override {
return "Division by zero!";
}
};
double divide(double a, double b) {
if (b == 0) {
throw DivideByZeroException(); // 抛出异常
}
return a / b;
}
int main() {
try {
double result = divide(10.0, 0.0);
std::cout << "Result: " << result << std::endl;
} catch (const DivideByZeroException& e) {
std::cerr << "Error: " << e.what() << std::endl; // 捕获并处理异常
} catch (...) {
std::cerr << "Unknown exception occurred!" << std::endl;
}
return 0;
}
8. 多线程编程(C++11 起)
cpp
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void worker() {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return ready; }); // 等待主线程通知
std::cout << "Worker thread is working!" << std::endl;
}
int main() {
std::thread t(worker);
// 做一些准备工作
{
std::lock_guard<std::mutex> lock(mtx);
ready = true;
}
cv.notify_one(); // 通知工作线程
t.join(); // 等待线程完成
return 0;
}