Effective C++进阶¶
📖 章节简介¶
本章将介绍Effective C++的进阶概念,包括运算符重载、继承与多态和模板基础。
上图概括了本章的三条主线:运算符重载、继承多态与模板泛型,便于建立整体学习框架。
➕ 运算符重载¶
1. 基本运算符重载¶
C++
// 运算符重载
#include <iostream>
#include <string>
#include <stdexcept>
using namespace std;
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);
}
// 重载乘法运算符
// 复数乘法公式: (a+bi)(c+di) = (ac-bd) + (ad+bc)i
Complex operator*(const Complex& other) const {
return Complex(
real * other.real - imag * other.imag,
real * other.imag + imag * other.real
);
}
// 重载除法运算符
// 复数除法: (a+bi)/(c+di) = ((ac+bd) + (bc-ad)i) / (c²+d²)
Complex operator/(const Complex& other) const {
double denominator = other.real * other.real + other.imag * other.imag; // 分母 = c²+d²
if (denominator == 0) {
throw std::invalid_argument("除数为零,无法进行复数除法");
}
return Complex(
(real * other.real + imag * other.imag) / denominator,
(imag * other.real - real * other.imag) / denominator
);
}
// 重载输出运算符
friend ostream& operator<<(ostream& os, const Complex& c) {
os << c.real;
if (c.imag >= 0) {
os << "+" << c.imag << "i";
} else {
os << c.imag << "i";
}
return os;
}
void display() const {
cout << real;
if (imag >= 0) {
cout << "+" << imag << "i";
} else {
cout << imag << "i";
}
cout << endl;
}
};
int main() {
Complex c1(3, 4);
Complex c2(1, 2);
cout << "c1 = ";
c1.display();
cout << "c2 = ";
c2.display();
Complex c3 = c1 + c2;
cout << "c1 + c2 = ";
c3.display();
Complex c4 = c1 - c2;
cout << "c1 - c2 = ";
c4.display();
Complex c5 = c1 * c2;
cout << "c1 * c2 = ";
c5.display();
Complex c6 = c1 / c2;
cout << "c1 / c2 = ";
c6.display();
cout << "c3: " << c3 << endl;
return 0;
}
2. 关系运算符重载¶
C++
// 关系运算符重载
#include <iostream>
#include <string>
using namespace std;
class Person {
private:
string name;
int age;
public:
Person(string n, int a) : name(n), age(a) {}
// 重载==运算符
bool operator==(const Person& other) const {
return name == other.name && age == other.age;
}
// 重载!=运算符
bool operator!=(const Person& other) const {
return !(*this == other);
}
// 重载<运算符
bool operator<(const Person& other) const {
return age < other.age;
}
// 重载>运算符
bool operator>(const Person& other) const {
return age > other.age;
}
void display() const {
cout << "姓名: " << name << ", 年龄: " << age << endl;
}
};
int main() {
Person p1("张三", 25);
Person p2("李四", 30);
Person p3("王五", 20);
cout << "p1: ";
p1.display();
cout << "p2: ";
p2.display();
cout << "p1 == p2: " << (p1 == p2 ? "是" : "否") << endl;
cout << "p1 < p3: " << (p1 < p3 ? "是" : "否") << endl;
return 0;
}
🧬 继承与多态¶
1. 虚函数¶
C++
// 虚函数与多态
#include <iostream>
#include <memory>
using namespace std;
class Shape {
public:
virtual ~Shape() = default;
virtual void draw() const {
cout << "绘制形状" << endl;
}
virtual double getArea() const = 0;
};
class Circle : public Shape {
private:
double radius;
public:
Circle(double r) : radius(r) {}
void draw() const override {
cout << "绘制圆形,半径: " << radius << endl;
}
double getArea() const override {
return 3.141592653589793 * radius * radius;
}
};
class Rectangle : public Shape {
private:
double width;
double height;
public:
Rectangle(double w, double h) : width(w), height(h) {}
void draw() const override {
cout << "绘制矩形,宽: " << width << ", 高: " << height << endl;
}
double getArea() const override {
return width * height;
}
};
// 通过基类引用调用虚函数,运行时根据实际类型执行对应的draw和getArea
void processShape(const Shape& shape) {
shape.draw();
cout << "面积: " << shape.getArea() << endl;
}
int main() {
// 使用智能指针管理多态对象,存入基类指针容器
vector<unique_ptr<Shape>> shapes;
shapes.push_back(make_unique<Circle>(5.0));
shapes.push_back(make_unique<Rectangle>(4.0, 3.0));
shapes.push_back(make_unique<Circle>(3.0));
cout << "多态遍历形状:" << endl;
for (const auto& shape : shapes) {
processShape(*shape);
cout << endl;
}
return 0;
}
2. 继承层次设计¶
C++
// 继承层次设计
#include <iostream>
#include <memory>
using namespace std;
class Animal {
public:
virtual ~Animal() = default;
virtual void makeSound() const {
cout << "动物发出声音" << endl;
}
void eat() const {
cout << "动物在吃东西" << endl;
}
};
class Dog : public Animal {
private:
string breed;
public:
Dog(string b) : breed(b) {}
void makeSound() const override {
cout << "汪汪叫" << endl;
}
void fetch() const {
cout << "狗去捡球" << endl;
}
string getBreed() const {
return breed;
}
};
class Cat : public Animal {
private:
string color;
public:
Cat(string c) : color(c) {}
void makeSound() const override {
cout << "喵喵叫" << endl;
}
void climb() const {
cout << "猫爬树" << endl;
}
string getColor() const {
return color;
}
};
void interact(const Animal& animal) {
animal.eat();
animal.makeSound();
}
int main() {
Dog dog("金毛");
Cat cat("橘猫");
cout << "与狗交互:" << endl;
interact(dog);
cout << endl;
cout << "与猫交互:" << endl;
interact(cat);
cout << endl;
return 0;
}
🎯 模板基础¶
1. 函数模板¶
C++
// 函数模板
#include <iostream>
using namespace std;
// 比较函数模板(命名为 my_max 避免与 std::max 冲突)
template <typename T>
T my_max(T a, T b) {
return (a > b) ? a : b;
}
// 交换函数模板(命名为 my_swap 避免与 std::swap 冲突)
template <typename T>
void my_swap(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}
// 冒泡排序模板:每轮将未排序部分的最大值"冒泡"到末尾
template <typename T>
void sortArray(T* arr, int size) {
for (int i = 0; i < size - 1; i++) {
for (int j = 0; j < size - i - 1; j++) { // size-i-1: 已排好的尾部无需再比较
if (arr[j] > arr[j + 1]) {
my_swap(arr[j], arr[j + 1]); // 相邻元素逆序则交换
}
}
}
}
int main() {
int intArr[] = {64, 34, 25, 12, 22, 11, 90};
double doubleArr[] = {3.14, 1.59, 2.71, 0.5, 0.25, 0.3};
cout << "整数数组排序前:" << endl;
for (int i = 0; i < 7; i++) {
cout << intArr[i] << " ";
}
cout << endl;
sortArray(intArr, 7);
cout << "整数数组排序后:" << endl;
for (int i = 0; i < 7; i++) {
cout << intArr[i] << " ";
}
cout << endl;
cout << "\n浮点数排序前:" << endl;
for (int i = 0; i < 6; i++) {
cout << doubleArr[i] << " ";
}
cout << endl;
sortArray(doubleArr, 6);
cout << "浮点数排序后:" << endl;
for (int i = 0; i < 6; i++) {
cout << doubleArr[i] << " ";
}
cout << endl;
cout << "\n最大整数: " << my_max(10, 20) << endl;
cout << "最大浮点数: " << my_max(3.14, 1.59) << endl;
return 0;
}
2. 类模板¶
C++
// 类模板
#include <iostream>
#include <vector>
using namespace std;
template <typename T>
class Stack {
private:
vector<T> data;
public:
Stack() = default;
void push(const T& value) {
data.push_back(value);
}
T pop() {
if (data.empty()) {
throw runtime_error("栈为空");
}
T value = data.back();
data.pop_back();
return value;
}
T peek() const {
if (data.empty()) {
throw runtime_error("栈为空");
}
return data.back();
}
bool isEmpty() const {
return data.empty();
}
int size() const {
return data.size();
}
};
int main() {
Stack<int> intStack;
// 入栈
intStack.push(10);
intStack.push(20);
intStack.push(30);
cout << "栈大小: " << intStack.size() << endl;
// 出栈
while (!intStack.isEmpty()) {
cout << "出栈: " << intStack.pop() << endl;
}
cout << "\n栈已空" << endl;
return 0;
}
💡 最佳实践¶
1. 运算符重载¶
C++
// 运算符重载
int main() {
// ✅ 好的做法:保持运算符的语义
class GoodClass {
public:
GoodClass(int value) : data(value) {}
GoodClass operator+(const GoodClass& other) const {
return GoodClass(data + other.data);
}
int getData() const { return data; }
private:
int data;
};
// ❌ 不好的做法:改变运算符的语义
class BadClass {
public:
BadClass(int value) : data(value) {}
BadClass operator+(const BadClass& other) const {
return BadClass(data - other.data); // 加法变减法
}
int getData() const { return data; }
private:
int data;
};
return 0;
}
2. 模板设计¶
C++
// 模板设计
// ✅ 好的做法:使用类型萃取
template <typename T>
void process(T value) {
cout << "处理: " << value << endl;
}
// ❌ 不好的做法:不检查类型
template <typename T>
void processBad(T value) {
if (sizeof(T) > 4) {
// 特殊处理
cout << "大对象" << endl;
} else {
// 普通处理
cout << "小对象" << endl;
}
}
int main() {
process(42);
process(3.14);
return 0;
}
📝 练习题¶
基础题¶
- 如何重载运算符?
- 虚函数有什么作用?
- 模板有什么优势?
进阶题¶
- 实现一个完整的复数类。
- 设计一个合理的继承层次。
- 实现一个模板容器类。
实践题¶
- 创建一个矩阵运算库。
- 实现一个智能指针包装器。
- 构建一个简单的序列化系统。
📚 推荐阅读¶
🔗 下一步¶
13-STL深入剖析 - 深入学习STL容器、算法与迭代器。