C++基础教育第五课:面向对象编程与类设计
以下是C++基础教育第五课,聚焦面向对象编程(OOP)核心概念,掌握构建复杂系统的蓝图设计方法:
C++基础教育第五课:面向对象编程与类设计
一、课程导语
"对象是现实世界的数字化镜像,类是对象的蓝图——本节课我们将学习如何用封装、继承和多态构建灵活可扩展的软件系统。"
二、核心知识点
-
类与对象:封装数据与行为
-
访问控制:public/private/protected
-
构造函数与析构函数生命周期
-
继承机制:is-a关系建模
-
多态实现:虚函数与动态绑定
三、实操环节
1. 类与对象:设计游戏角色系统
(1) 基础类定义
#include <iostream>
#include <string>
using namespace std;
class Character {
private: // 封装内部数据
string name;
int health;
int attackPower;
public: // 对外接口
// 构造函数
Character(string n, int h, int ap)
: name(n), health(h), attackPower(ap) {}
// 成员函数
void attack(Character &target) {
cout << name << " 攻击 " << target.name
<< ",造成 " << attackPower << " 点伤害!" << endl;
target.health -= attackPower;
}
void displayStatus() const {
cout << name << " [生命值: " << health
<< ", 攻击力: " << attackPower << "]" << endl;
}
};
int main() {
Character hero("勇者", 100, 15);
Character monster("恶龙", 150, 10);
hero.attack(monster);
monster.displayStatus(); // 输出: 恶龙 [生命值: 140, 攻击力: 10]
return 0;
}
关键设计原则:
-
数据隐藏(private成员)
-
明确接口边界(public方法)
(2) 构造函数进阶
class Player {
private:
string username;
int level;
double exp;
public:
// 默认构造函数
Player() : username("匿名玩家"), level(1), exp(0.0) {}
// 参数化构造函数
Player(string name, int lvl = 1) // 默认参数
: username(name), level(lvl), exp(0.0) {}
// 拷贝构造函数
Player(const Player &other)
: username(other.username + "_副本"),
level(other.level),
exp(other.exp) {}
// 移动构造函数 (C++11)
Player(Player &&other) noexcept
: username(move(other.username)),
level(other.level),
exp(other.exp) {
other.level = 0; // 置空源对象
}
};
// 使用示例
Player p1; // 调用默认构造函数
Player p2("艾琳"); // 调用参数化构造函数
Player p3 = p2; // 调用拷贝构造函数
Player p4 = move(p2); // 调用移动构造函数
2. 继承机制:打造游戏职业体系
(1) 基础继承模型
// 基类
class Warrior : public Character { // public继承保持is-a关系
public:
Warrior(string n) : Character(n, 120, 20) {} // 战士初始属性
void shout() const {
cout << name << " 发出战吼!" << endl; // 可访问基类protected成员
}
};
// 派生类
class Mage : public Character {
private:
int mana;
public:
Mage(string n) : Character(n, 80, 8), mana(100) {}
void castSpell() {
if(mana >= 20) {
cout << name << " 释放火球术!" << endl;
mana -= 20;
} else {
cout << "法力不足!" << endl;
}
}
};
int main() {
Warrior conan("柯南");
Mage gandalf("甘道夫");
conan.attack(gandalf); // 继承自Character的方法
gandalf.castSpell(); // Mage特有方法
return 0;
}
继承关系图示:
Character (基类)
├── Warrior (派生类)
└── Mage (派生类)
(2) 继承中的访问控制
| 基类成员访问权限 | 派生类访问权限(public继承) |
|---|---|
| public | public |
| protected | protected |
| private | 不可访问 |
特殊继承方式:
class Priest : protected Character { // protected继承
// Character的public成员在Priest中变为protected
};
class ShadowAssassin : private Character { // private继承
// Character的所有成员在ShadowAssassin中变为private
}
3. 多态实现:战斗系统动态绑定
(1) 虚函数与动态绑定
class Character {
public:
virtual void specialAbility() { // 虚函数声明
cout << "基础角色技能" << endl;
}
virtual ~Character() {} // 虚析构函数(关键!)
};
class Paladin : public Character {
public:
void specialAbility() override { // 重写虚函数
cout << "圣光审判!" << endl;
}
};
class Assassin : public Character {
public:
void specialAbility() override {
cout << "暗影突袭!" << endl;
}
};
void battle(Character &c) { // 接受基类引用
c.specialAbility(); // 运行时决定调用哪个版本
}
int main() {
Paladin p;
Assassin a;
battle(p); // 输出: 圣光审判!
battle(a); // 输出: 暗影突袭!
return 0;
}
虚函数表(vtable)机制:
-
每个含虚函数的类维护一个虚函数表
-
对象内存头部存储vptr指针指向vtable
-
调用时通过vptr查找正确函数地址
(2) 抽象类与纯虚函数
class Shape { // 抽象类(不能实例化)
public:
virtual double area() const = 0; // 纯虚函数
virtual void draw() const = 0;
};
class Circle : public Shape {
private:
double radius;
public:
Circle(double r) : radius(r) {}
double area() const override {
return 3.14159 * radius * radius;
}
void draw() const override {
cout << "绘制圆形" << endl;
}
};
int main() {
// Shape s; // 错误!不能实例化抽象类
Circle c(5.0);
cout << "圆面积: " << c.area() << endl;
return 0;
}
四、底层原理剖析
1. 对象内存布局
简单类的内存结构:
+---------+
| name | // string类型(实际包含指针等复杂结构)
+---------+
| health | // int (4字节)
+---------+
| attackPower | // int (4字节)
+---------+
包含虚函数的类额外增加:
+---------+
| vptr | // 指向虚函数表(vtable)
+---------+
| name |
+---------+
| health |
+---------+
| attackPower |
+---------+
2. 继承内存模型
class Base { int a; };
class Derived : public Base { int b; };
内存布局:
+---------+
| a (Base) |
+---------+
| b (Derived) |
+---------+
3. 多态实现成本
-
空间开销:每个对象增加vptr指针(通常4/8字节)
-
时间开销:虚函数调用需间接寻址(多一次指针解引用)
五、课后实战任务
基础挑战
-
实现银行账户系统:
-
基类
Account(账号、余额、存取款方法) -
派生类
SavingsAccount(增加利息计算) -
派生类
CheckingAccount(增加透支保护)
-
进阶挑战
-
设计图形编辑器框架:
-
抽象基类
GraphicObject(绘制、移动、缩放接口) -
派生类
Circle、Rectangle、Polygon -
实现对象组合模式(支持复杂图形)
-
-
实现多态工厂模式:
class Product { public: virtual void use() = 0; }; class Factory { public: virtual Product* createProduct() = 0; }; // 具体工厂与产品实现...
六、常见问题解答
-
Q:什么时候应该使用继承?
A:
-
严格满足"is-a"关系时(学生is-a人)
-
需要多态行为时
-
避免滥用继承(优先考虑组合关系"has-a")
-
-
Q:虚函数为什么需要虚析构函数?
A:
-
确保通过基类指针删除派生类对象时
-
能正确调用派生类的析构函数
-
防止内存泄漏
-
-
Q:override和final关键字的作用?
A:
-
override:显式标记重写虚函数(编译器检查匹配性) -
final:禁止派生类进一步重写虚函数或继承类
-
"面向对象编程是管理复杂度的艺术——通过抽象和分层,你已获得构建大型系统的钥匙!"
(本课代码已在C++17标准下验证,推荐使用Clang-Tidy进行代码规范检查)
更多推荐



所有评论(0)