Kế thừa (Inheritance)
📖 Giới thiệu
Kế thừa cho phép một lớp (lớp con) được tạo ra dựa trên lớp khác (lớp cha), thừa hưởng các thuộc tính và phương thức. Điều này giúp tái sử dụng code và tạo ra cấu trúc phân cấp hợp lý.
Ví dụ đơn giản đầu tiên
cpp
#include <iostream>
#include <string>
using namespace std;
// Lớp cha
class ConVat {
protected:
string ten;
int tuoi;
public:
ConVat(string t, int tuoi_moi) {
ten = t;
tuoi = tuoi_moi;
}
void an() {
cout << ten << " đang ăn" << endl;
}
void ngu() {
cout << ten << " đang ngủ" << endl;
}
};
// Lớp con
class Cho : public ConVat {
public:
Cho(string t, int tuoi_moi) : ConVat(t, tuoi_moi) {
}
void sua() { // Phương thức riêng của chó
cout << ten << " đang sủa: Gâu gâu!" << endl;
}
};
int main() {
Cho cho1("Buddy", 3);
cho1.an(); // Từ lớp cha
cho1.ngu(); // Từ lớp cha
cho1.sua(); // Từ lớp con
return 0;
}🔧 Cú pháp
Kế thừa cơ bản
cpp
class LopCha {
protected:
int thuocTinhChung;
public:
void phuongThucChung() { }
};
class LopCon : public LopCha {
private:
int thuocTinhRieng;
public:
void phuongThucRieng() { }
};Các loại kế thừa
cpp
// Public inheritance
class Con : public Cha { };
// Protected inheritance
class Con : protected Cha { };
// Private inheritance
class Con : private Cha { };Gọi constructor của lớp cha
cpp
class LopCon : public LopCha {
public:
LopCon(int gia_tri) : LopCha(gia_tri) {
// Constructor của lớp con
}
};🔬 Phân tích & Giải thích
Các loại kế thừa trong C++
1. Public Inheritance: Quan hệ "is-a"
cpp
class Xe {
protected:
string hang;
int nam_san_xuat;
public:
void khoi_dong() {
cout << "Xe đã khởi động" << endl;
}
};
class XeHoi : public Xe { // XeHoi IS-A Xe
private:
int so_cua;
public:
void mo_cua() {
cout << "Mở " << so_cua << " cửa xe" << endl;
}
};2. Protected Inheritance: Ít sử dụng
cpp
class B : protected A {
// public và protected của A trở thành protected trong B
};3. Private Inheritance: Quan hệ "implemented-in-terms-of"
cpp
class C : private A {
// Tất cả thành viên của A trở thành private trong C
};Phạm vi truy cập trong kế thừa
| Lớp cha | public | protected | private |
|---|---|---|---|
| public | public | protected | private |
| protected | protected | protected | private |
| private | private | private | private |
💻 Ví dụ minh họa
Ví dụ 1: Hệ thống quản lý nhân viên
cpp
#include <iostream>
#include <string>
using namespace std;
// Lớp cha - Nhân viên
class NhanVien {
protected:
string ho_ten;
string ma_nv;
int tuoi;
double luong_co_ban;
public:
NhanVien(string ten, string ma, int tuoi_nv, double luong) {
ho_ten = ten;
ma_nv = ma;
tuoi = tuoi_nv;
luong_co_ban = luong;
cout << "Tạo nhân viên: " << ho_ten << endl;
}
virtual ~NhanVien() {
cout << "Xóa nhân viên: " << ho_ten << endl;
}
void hien_thong_tin_co_ban() {
cout << "=== THÔNG TIN NHÂN VIÊN ===" << endl;
cout << "Họ tên: " << ho_ten << endl;
cout << "Mã NV: " << ma_nv << endl;
cout << "Tuổi: " << tuoi << endl;
cout << "Lương cơ bản: " << luong_co_ban << " VND" << endl;
}
virtual double tinh_luong() {
return luong_co_ban;
}
virtual void lam_viec() {
cout << ho_ten << " đang làm việc" << endl;
}
// Getter methods
string lay_ten() const { return ho_ten; }
string lay_ma_nv() const { return ma_nv; }
};
// Lớp con 1 - Nhân viên văn phòng
class NhanVienVanPhong : public NhanVien {
private:
double phu_cap_an_trua;
double phu_cap_xang_xe;
public:
NhanVienVanPhong(string ten, string ma, int tuoi_nv, double luong,
double an_trua = 500000, double xang_xe = 300000)
: NhanVien(ten, ma, tuoi_nv, luong) {
phu_cap_an_trua = an_trua;
phu_cap_xang_xe = xang_xe;
cout << "Phân loại: Nhân viên văn phòng" << endl;
}
double tinh_luong() override {
return luong_co_ban + phu_cap_an_trua + phu_cap_xang_xe;
}
void lam_viec() override {
cout << ho_ten << " đang làm việc tại văn phòng" << endl;
}
void hop_online() {
cout << ho_ten << " đang tham gia họp online" << endl;
}
void hien_thong_tin_chi_tiet() {
hien_thong_tin_co_ban();
cout << "Phụ cấp ăn trua: " << phu_cap_an_trua << " VND" << endl;
cout << "Phụ cấp xăng xe: " << phu_cap_xang_xe << " VND" << endl;
cout << "Tổng lương: " << tinh_luong() << " VND" << endl;
cout << "============================" << endl;
}
};
// Lớp con 2 - Nhân viên bán hàng
class NhanVienBanHang : public NhanVien {
private:
double doanh_so;
double ty_le_hoa_hong;
public:
NhanVienBanHang(string ten, string ma, int tuoi_nv, double luong,
double ty_le = 0.02)
: NhanVien(ten, ma, tuoi_nv, luong) {
doanh_so = 0;
ty_le_hoa_hong = ty_le;
cout << "Phân loại: Nhân viên bán hàng" << endl;
}
double tinh_luong() override {
return luong_co_ban + (doanh_so * ty_le_hoa_hong);
}
void lam_viec() override {
cout << ho_ten << " đang bán hàng và tư vấn khách hàng" << endl;
}
void cap_nhat_doanh_so(double doanh_so_moi) {
doanh_so += doanh_so_moi;
cout << ho_ten << " có doanh số mới: " << doanh_so_moi
<< " VND. Tổng doanh số: " << doanh_so << " VND" << endl;
}
void ban_hang() {
cout << ho_ten << " đang thuyết phục khách hàng mua hàng" << endl;
}
void hien_thong_tin_chi_tiet() {
hien_thong_tin_co_ban();
cout << "Doanh số: " << doanh_so << " VND" << endl;
cout << "Tỷ lệ hoa hồng: " << (ty_le_hoa_hong * 100) << "%" << endl;
cout << "Hoa hồng: " << (doanh_so * ty_le_hoa_hong) << " VND" << endl;
cout << "Tổng lương: " << tinh_luong() << " VND" << endl;
cout << "============================" << endl;
}
};
// Lớp con 3 - Quản lý
class QuanLy : public NhanVien {
private:
int so_nhan_vien_quan_ly;
double thuong_quan_ly;
public:
QuanLy(string ten, string ma, int tuoi_nv, double luong, int so_nv = 0)
: NhanVien(ten, ma, tuoi_nv, luong) {
so_nhan_vien_quan_ly = so_nv;
thuong_quan_ly = so_nv * 500000; // 500k cho mỗi nhân viên quản lý
cout << "Phân loại: Quản lý cấp cao" << endl;
}
double tinh_luong() override {
return luong_co_ban + thuong_quan_ly;
}
void lam_viec() override {
cout << ho_ten << " đang quản lý " << so_nhan_vien_quan_ly << " nhân viên" << endl;
}
void hop_quan_ly() {
cout << ho_ten << " đang tổ chức họp quản lý" << endl;
}
void danh_gia_nhan_vien() {
cout << ho_ten << " đang đánh giá hiệu suất nhân viên" << endl;
}
void them_nhan_vien_quan_ly() {
so_nhan_vien_quan_ly++;
thuong_quan_ly = so_nhan_vien_quan_ly * 500000;
cout << ho_ten << " quản lý thêm 1 nhân viên. Tổng: "
<< so_nhan_vien_quan_ly << " nhân viên" << endl;
}
void hien_thong_tin_chi_tiet() {
hien_thong_tin_co_ban();
cout << "Số nhân viên quản lý: " << so_nhan_vien_quan_ly << endl;
cout << "Thưởng quản lý: " << thuong_quan_ly << " VND" << endl;
cout << "Tổng lương: " << tinh_luong() << " VND" << endl;
cout << "============================" << endl;
}
};
int main() {
cout << "=== HỆ THỐNG QUẢN LÝ NHÂN VIÊN ===" << endl;
// Tạo các nhân viên
NhanVienVanPhong nv1("Nguyễn Văn A", "NV001", 28, 8000000);
NhanVienBanHang nv2("Trần Thị B", "NV002", 25, 6000000, 0.03);
QuanLy ql1("Lê Văn C", "QL001", 35, 15000000, 5);
cout << "\n=== THÔNG TIN CHI TIẾT ===" << endl;
nv1.hien_thong_tin_chi_tiet();
nv2.hien_thong_tin_chi_tiet();
ql1.hien_thong_tin_chi_tiet();
cout << "\n=== HOẠT ĐỘNG CÔNG VIỆC ===" << endl;
nv1.lam_viec();
nv1.hop_online();
nv2.lam_viec();
nv2.ban_hang();
nv2.cap_nhat_doanh_so(10000000);
ql1.lam_viec();
ql1.hop_quan_ly();
ql1.danh_gia_nhan_vien();
cout << "\n=== CẬP NHẬT THÔNG TIN ===" << endl;
ql1.them_nhan_vien_quan_ly();
cout << "\n=== LƯƠNG SAU CẬP NHẬT ===" << endl;
nv2.hien_thong_tin_chi_tiet();
ql1.hien_thong_tin_chi_tiet();
return 0;
}Ví dụ 2: Game với các loại nhân vật
cpp
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
// Lớp cha - Nhân vật game
class GameCharacter {
protected:
string ten;
int level;
int hp;
int max_hp;
int mp;
int max_mp;
public:
GameCharacter(string name, int lvl = 1) {
ten = name;
level = lvl;
max_hp = 100 * level;
max_mp = 50 * level;
hp = max_hp;
mp = max_mp;
cout << "Tạo nhân vật: " << ten << " (Level " << level << ")" << endl;
}
virtual ~GameCharacter() {
cout << ten << " rời khỏi game!" << endl;
}
virtual int attack() {
if (mp >= 10) {
mp -= 10;
int damage = 20 + level * 5;
cout << ten << " tấn công cơ bản - Damage: " << damage << endl;
return damage;
}
cout << ten << " không đủ MP!" << endl;
return 0;
}
virtual void take_damage(int damage) {
hp = max(0, hp - damage);
cout << ten << " nhận " << damage << " sát thương. HP: "
<< hp << "/" << max_hp << endl;
}
virtual void heal() {
hp = min(max_hp, hp + 30);
cout << ten << " hồi phục 30 HP. HP hiện tại: " << hp << endl;
}
bool is_alive() const {
return hp > 0;
}
virtual void show_stats() {
cout << "\n=== " << ten << " ===" << endl;
cout << "Level: " << level << endl;
cout << "HP: " << hp << "/" << max_hp << endl;
cout << "MP: " << mp << "/" << max_mp << endl;
}
string get_name() const { return ten; }
int get_level() const { return level; }
};
// Lớp con 1 - Chiến binh
class Warrior : public GameCharacter {
private:
int armor;
int strength;
public:
Warrior(string name, int lvl = 1) : GameCharacter(name, lvl) {
armor = 10 + level * 3;
strength = 15 + level * 5;
cout << "Lớp: Chiến Binh (Armor: " << armor << ", Strength: " << strength << ")" << endl;
}
int attack() override {
if (mp >= 15) {
mp -= 15;
int damage = strength + 30 + (rand() % 20);
cout << "⚔️ " << ten << " tấn công mạnh - Damage: " << damage << endl;
return damage;
} else if (mp >= 10) {
return GameCharacter::attack();
}
cout << ten << " không đủ MP!" << endl;
return 0;
}
void take_damage(int damage) override {
int reduced_damage = max(1, damage - armor);
GameCharacter::take_damage(reduced_damage);
}
void shield_bash() {
if (mp >= 20) {
mp -= 20;
cout << "🛡️ " << ten << " sử dụng Shield Bash!" << endl;
} else {
cout << ten << " không đủ MP cho Shield Bash!" << endl;
}
}
void show_stats() override {
GameCharacter::show_stats();
cout << "Armor: " << armor << endl;
cout << "Strength: " << strength << endl;
cout << "===============" << endl;
}
};
// Lớp con 2 - Pháp sư
class Mage : public GameCharacter {
private:
int intelligence;
int mana_regen;
public:
Mage(string name, int lvl = 1) : GameCharacter(name, lvl) {
intelligence = 20 + level * 8;
mana_regen = 5 + level * 2;
max_mp = 80 * level; // Pháp sư có nhiều MP hơn
mp = max_mp;
cout << "Lớp: Pháp Sư (Intelligence: " << intelligence << ")" << endl;
}
int attack() override {
if (mp >= 25) {
mp -= 25;
int damage = intelligence + 40 + (rand() % 30);
cout << "🔥 " << ten << " phép thuật lửa - Damage: " << damage << endl;
return damage;
} else if (mp >= 10) {
return GameCharacter::attack();
}
cout << ten << " không đủ MP!" << endl;
return 0;
}
void heal() override {
if (mp >= 20) {
mp -= 20;
hp = min(max_hp, hp + 50);
cout << "✨ " << ten << " phép thuật hồi phục 50 HP" << endl;
} else {
GameCharacter::heal();
}
}
void ice_storm() {
if (mp >= 40) {
mp -= 40;
cout << "❄️ " << ten << " sử dụng Ice Storm - AOE damage!" << endl;
} else {
cout << ten << " không đủ MP cho Ice Storm!" << endl;
}
}
void mana_recovery() {
mp = min(max_mp, mp + mana_regen);
cout << "💙 " << ten << " hồi phục " << mana_regen << " MP" << endl;
}
void show_stats() override {
GameCharacter::show_stats();
cout << "Intelligence: " << intelligence << endl;
cout << "Mana Regen: " << mana_regen << endl;
cout << "===============" << endl;
}
};
// Lớp con 3 - Cung thủ
class Archer : public GameCharacter {
private:
int agility;
int accuracy;
public:
Archer(string name, int lvl = 1) : GameCharacter(name, lvl) {
agility = 18 + level * 6;
accuracy = 85 + level * 3; // Phần trăm trúng đích
cout << "Lớp: Cung Thủ (Agility: " << agility << ", Accuracy: " << accuracy << "%)" << endl;
}
int attack() override {
if (mp >= 12) {
mp -= 12;
int hit_chance = rand() % 100;
if (hit_chance < accuracy) {
int damage = agility + 25 + (rand() % 25);
cout << "🏹 " << ten << " bắn trúng mục tiêu - Damage: " << damage << endl;
return damage;
} else {
cout << "🏹 " << ten << " bắn trượt mục tiêu!" << endl;
return 0;
}
}
return GameCharacter::attack();
}
void power_shot() {
if (mp >= 30) {
mp -= 30;
int damage = agility * 2 + 50;
cout << "🎯 " << ten << " Power Shot - Damage: " << damage << endl;
} else {
cout << ten << " không đủ MP cho Power Shot!" << endl;
}
}
void dodge() {
cout << "💨 " << ten << " né tránh tấn công!" << endl;
}
void show_stats() override {
GameCharacter::show_stats();
cout << "Agility: " << agility << endl;
cout << "Accuracy: " << accuracy << "%" << endl;
cout << "===============" << endl;
}
};
int main() {
cout << "=== GAME RPG - BATTLE SYSTEM ===" << endl;
// Tạo party
Warrior tank("Thor", 3);
Mage wizard("Gandalf", 3);
Archer ranger("Legolas", 3);
cout << "\n=== THÔNG TIN PARTY ===" << endl;
tank.show_stats();
wizard.show_stats();
ranger.show_stats();
cout << "\n=== TRẬN CHIẾN ===" << endl;
// Tạo quái vật
GameCharacter dragon("Ancient Dragon", 5);
int turn = 1;
while (dragon.is_alive() && (tank.is_alive() || wizard.is_alive() || ranger.is_alive())) {
cout << "\n--- Lượt " << turn << " ---" << endl;
// Party tấn công
if (tank.is_alive()) {
int damage = tank.attack();
dragon.take_damage(damage);
tank.shield_bash();
}
if (wizard.is_alive() && dragon.is_alive()) {
wizard.mana_recovery();
int damage = wizard.attack();
dragon.take_damage(damage);
}
if (ranger.is_alive() && dragon.is_alive()) {
int damage = ranger.attack();
dragon.take_damage(damage);
ranger.power_shot();
}
if (!dragon.is_alive()) {
cout << "\n🏆 Party chiến thắng!" << endl;
break;
}
// Dragon phản công
if (tank.is_alive()) {
tank.take_damage(60);
} else if (wizard.is_alive()) {
wizard.take_damage(60);
} else if (ranger.is_alive()) {
ranger.take_damage(60);
}
// Hồi phục
if (turn % 3 == 0) {
if (tank.is_alive()) tank.heal();
if (wizard.is_alive()) wizard.heal();
if (ranger.is_alive()) ranger.heal();
}
turn++;
if (turn > 8) break; // Giới hạn số lượt
}
cout << "\n=== KẾT QUẢ CUỐI ===" << endl;
tank.show_stats();
wizard.show_stats();
ranger.show_stats();
return 0;
}🏋️ Thực hành
Bài tập 1: Hệ thống xe cộ
Tạo lớp Xe và các lớp con XeMay, XeHoi, XeTai với:
- Lớp cha: thuộc tính chung và phương thức cơ bản
- Lớp con: thuộc tính riêng và override phương thức
Bài tập 2: Quản lý học sinh
Tạo lớp HocSinh và các lớp con theo khối lớp:
HocSinhTieuHoc,HocSinhTrungHoc,HocSinhPhoBang- Mỗi lớp có cách tính điểm khác nhau
Bài tập 3: Hình học
Tạo lớp Hinh và các lớp con HinhTron, HinhVuong, HinhChuNhat:
- Phương thức ảo tính diện tích và chu vi
- Mỗi hình có công thức riêng
📋 Tóm tắt
Kế thừa: Cho phép lớp con thừa hưởng từ lớp cha
Cú pháp:
class LopCon : public LopChaPhạm vi truy cập:
public: Thành viên public và protected của cha vẫn như cũprotected: Thành viên public của cha thành protectedprivate: Tất cả thành viên của cha thành private
Constructor: Lớp con phải gọi constructor lớp cha
Lợi ích:
- Tái sử dụng code
- Tạo cấu trúc phân cấp
- Dễ bảo trì và mở rộng
Bài tiếp theo: Đa hình - Tìm hiểu về overriding và virtual functions.