本章将深入探讨C++的面向对象核心特性——继承与多态,包括继承类型、虚函数、纯虚函数、抽象类等概念。
继承允许创建基于现有类的新类,实现代码复用和层次化设计。
#include <iostream> #include <string> using namespace std; // 基类(父类) class Person { protected: string name; int age; public: Person(string n, int a) : name(n), age(a) { cout << "Person constructor" << endl; } void introduce() const { cout << "I am " << name << ", " << age << " years old." << endl; } void eat() const { cout << name << " is eating." << endl; } void sleep() const { cout << name << " is sleeping." << endl; } }; // 派生类(子类) class Student : public Person { private: string school; int studentId; public: // 派生类构造函数 Student(string n, int a, string s, int id) : Person(n, a), school(s), studentId(id) { cout << "Student constructor" << endl; } void study() const { cout << name << " is studying at " << school << "." << endl; } void showInfo() const { introduce(); cout << "School: " << school << ", ID: " << studentId << endl; } }; // 另一个派生类 class Teacher : public Person { private: string subject; double salary; public: Teacher(string n, int a, string sub, double sal) : Person(n, a), subject(sub), salary(sal) {} void teach() const { cout << name << " is teaching " << subject << "." << endl; } }; int main() { Student stu("Alice", 20, "MIT", 12345); Teacher tea("Bob", 35, "Mathematics", 5000); stu.introduce(); // 继承自Person stu.eat(); // 继承自Person stu.study(); // Student自己的方法 tea.teach(); return 0; }
| 继承方式 | 基类public成员 | 基类protected成员 | 基类private成员 |
| ——— | ————– | —————— | —————- |
| public继承 | public | protected | 不可访问 |
| protected继承 | protected | protected | 不可访问 |
| private继承 | private | private | 不可访问 |
#include <iostream> using namespace std; class Base { public: int publicVar = 1; protected: int protectedVar = 2; private: int privateVar = 3; }; // public继承(最常用) class PublicDerived : public Base { public: void test() { cout << publicVar << endl; // OK,保持public cout << protectedVar << endl; // OK,保持protected // cout << privateVar << endl; // 错误!不可访问 } }; // protected继承 class ProtectedDerived : protected Base { public: void test() { cout << publicVar << endl; // OK,变为protected cout << protectedVar << endl; // OK,保持protected } }; // private继承(实现继承) class PrivateDerived : private Base { public: void test() { cout << publicVar << endl; // OK,变为private cout << protectedVar << endl; // OK,变为private } }; int main() { PublicDerived pub; cout << pub.publicVar << endl; // OK ProtectedDerived pro; // cout << pro.publicVar << endl; // 错误!变为protected return 0; }
#include <iostream> using namespace std; class GrandParent { public: GrandParent() { cout << "GrandParent constructor" << endl; } ~GrandParent() { cout << "GrandParent destructor" << endl; } }; class Parent : public GrandParent { public: Parent() { cout << "Parent constructor" << endl; } ~Parent() { cout << "Parent destructor" << endl; } }; class Child : public Parent { public: Child() { cout << "Child constructor" << endl; } ~Child() { cout << "Child destructor" << endl; } }; int main() { cout << "Creating Child object:" << endl; Child c; cout << "Child object created" << endl; // 输出顺序: // GrandParent constructor // Parent constructor // Child constructor // Child object created // Child destructor // Parent destructor // GrandParent destructor return 0; }
#include <iostream> #include <string> using namespace std; class Person { protected: string name; int age; public: Person(string n, int a) : name(n), age(a) { cout << "Person(" << name << ", " << age << ")" << endl; } }; class Student : public Person { private: int studentId; public: // 向基类构造函数传递参数 Student(string n, int a, int id) : Person(n, a), studentId(id) { cout << "Student(" << studentId << ")" << endl; } }; class GraduateStudent : public Student { private: string researchTopic; public: GraduateStudent(string n, int a, int id, string topic) : Student(n, a, id), researchTopic(topic) { cout << "GraduateStudent(" << researchTopic << ")" << endl; } }; int main() { GraduateStudent gs("Alice", 25, 12345, "AI"); return 0; }
虚函数允许派生类重写基类的方法,实现运行时多态。
#include <iostream> using namespace std; class Shape { public: // 虚函数 virtual double getArea() const { cout << "Shape::getArea" << endl; return 0; } // 虚函数可以有自己的实现 virtual void draw() const { cout << "Drawing a shape" << endl; } // 非虚函数 void print() const { cout << "This is a shape" << endl; } }; class Circle : public Shape { private: double radius; public: Circle(double r) : radius(r) {} // 重写虚函数(override关键字C++11) double getArea() const override { return 3.14159 * radius * radius; } void draw() const override { cout << "Drawing a circle with radius " << radius << endl; } }; class Rectangle : public Shape { private: double width, height; public: Rectangle(double w, double h) : width(w), height(h) {} double getArea() const override { return width * height; } void draw() const override { cout << "Drawing a rectangle " << width << "x" << height << endl; } }; int main() { Circle c(5); Rectangle r(4, 6); // 通过基类指针实现多态 Shape* shape1 = &c; Shape* shape2 = &r; shape1->draw(); // 调用Circle::draw shape2->draw(); // 调用Rectangle::draw cout << "Area1: " << shape1->getArea() << endl; // 78.5397 cout << "Area2: " << shape2->getArea() << endl; // 24 // 非虚函数没有多态性 shape1->print(); // 调用Shape::print return 0; }
#include <iostream> using namespace std; class Base { public: virtual void func1() { cout << "Base::func1" << endl; } virtual void func2() { cout << "Base::func2" << endl; } void func3() { cout << "Base::func3" << endl; } }; class Derived : public Base { public: void func1() override { cout << "Derived::func1" << endl; } void func2() override { cout << "Derived::func2" << endl; } void func3() { cout << "Derived::func3" << endl; } }; int main() { cout << "sizeof(Base) = " << sizeof(Base) << endl; // 包含虚表指针 cout << "sizeof(Derived) = " << sizeof(Derived) << endl; Base* b = new Derived(); // 通过虚表调用(运行时绑定) b->func1(); // Derived::func1 b->func2(); // Derived::func2 // 非虚函数,编译时绑定 b->func3(); // Base::func3 delete b; return 0; }
#include <iostream> #include <string> using namespace std; // 抽象类 class Animal { protected: string name; int age; public: Animal(string n, int a) : name(n), age(a) {} // 纯虚函数 = 0 virtual void speak() const = 0; virtual void move() const = 0; // 普通虚函数 virtual void info() const { cout << name << " is " << age << " years old." << endl; } // 虚析构函数(重要!) virtual ~Animal() { cout << "Animal destructor" << endl; } }; // 派生类必须实现所有纯虚函数 class Dog : public Animal { public: Dog(string n, int a) : Animal(n, a) {} void speak() const override { cout << name << " says: Woof!" << endl; } void move() const override { cout << name << " is running on four legs." << endl; } ~Dog() { cout << "Dog destructor" << endl; } }; class Cat : public Animal { public: Cat(string n, int a) : Animal(n, a) {} void speak() const override { cout << name << " says: Meow!" << endl; } void move() const override { cout << name << " is walking silently." << endl; } ~Cat() { cout << "Cat destructor" << endl; } }; class Bird : public Animal { public: Bird(string n, int a) : Animal(n, a) {} void speak() const override { cout << name << " says: Tweet!" << endl; } void move() const override { cout << name << " is flying in the sky." << endl; } void info() const override { Animal::info(); cout << name << " can fly!" << endl; } ~Bird() { cout << "Bird destructor" << endl; } }; int main() { // Animal a; // 错误!不能实例化抽象类 Animal* animals[] = { new Dog("Buddy", 3), new Cat("Whiskers", 2), new Bird("Tweety", 1) }; for (Animal* animal : animals) { animal->info(); animal->speak(); animal->move(); cout << endl; } // 如果基类析构函数不是虚函数,这里会内存泄漏! for (Animal* animal : animals) { delete animal; } return 0; }
#include <iostream> using namespace std; // 纯接口类(所有函数都是纯虚函数) class IPrintable { public: virtual void print() const = 0; virtual ~IPrintable() = default; }; class ISerializable { public: virtual string serialize() const = 0; virtual void deserialize(const string& data) = 0; virtual ~ISerializable() = default; }; // 多重继承实现多个接口 class Document : public IPrintable, public ISerializable { private: string title; string content; public: Document(string t, string c) : title(t), content(c) {} void print() const override { cout << "Title: " << title << endl; cout << "Content: " << content << endl; } string serialize() const override { return title + "|" + content; } void deserialize(const string& data) override { size_t pos = data.find('|'); title = data.substr(0, pos); content = data.substr(pos + 1); } }; int main() { Document doc("Report", "This is the report content."); IPrintable* p = &doc; ISerializable* s = &doc; p->print(); string serialized = s->serialize(); cout << "Serialized: " << serialized << endl; return 0; }
#include <iostream> using namespace std; // 错误的例子:基类析构函数不是虚函数 class BadBase { public: ~BadBase() { cout << "BadBase destructor" << endl; } }; class BadDerived : public BadBase { private: int* data; public: BadDerived() { data = new int[100]; } ~BadDerived() { delete[] data; cout << "BadDerived destructor" << endl; } }; // 正确的例子:基类析构函数是虚函数 class GoodBase { public: virtual ~GoodBase() { cout << "GoodBase destructor" << endl; } }; class GoodDerived : public GoodBase { private: int* data; public: GoodDerived() { data = new int[100]; } ~GoodDerived() override { delete[] data; cout << "GoodDerived destructor" << endl; } }; int main() { cout << "=== Bad Example ===" << endl; BadBase* bad = new BadDerived(); delete bad; // 只调用BadBase的析构函数,内存泄漏! cout << "\n=== Good Example ===" << endl; GoodBase* good = new GoodDerived(); delete good; // 先调用GoodDerived,再调用GoodBase的析构函数 return 0; }
#include <iostream> using namespace std; class Camera { public: void takePhoto() { cout << "Taking a photo" << endl; } }; class Phone { public: void makeCall() { cout << "Making a call" << endl; } }; class Smartphone : public Camera, public Phone { public: void browseInternet() { cout << "Browsing the internet" << endl; } }; int main() { Smartphone sp; sp.takePhoto(); // 继承自Camera sp.makeCall(); // 继承自Phone sp.browseInternet(); // 自己的方法 return 0; }
#include <iostream> using namespace std; class Person { public: string name; Person(string n) : name(n) { cout << "Person constructor" << endl; } }; // 使用虚继承解决菱形问题 class Student : virtual public Person { public: int studentId; Student(string n, int id) : Person(n), studentId(id) { cout << "Student constructor" << endl; } }; class Employee : virtual public Person { public: int employeeId; Employee(string n, int id) : Person(n), employeeId(id) { cout << "Employee constructor" << endl; } }; // 虚继承时,由最派生类调用基类构造函数 class WorkingStudent : public Student, public Employee { public: WorkingStudent(string n, int sid, int eid) : Person(n), Student(n, sid), Employee(n, eid) { cout << "WorkingStudent constructor" << endl; } }; int main() { WorkingStudent ws("Alice", 12345, 67890); // 没有虚继承时,name会有两份拷贝 // ws.Student::name = "Bob"; // ws.Employee::name = "Charlie"; // 混乱! // 使用虚继承后,只有一份name cout << "Name: " << ws.name << endl; return 0; }
#include <iostream> #include <typeinfo> using namespace std; class Base { public: virtual ~Base() = default; // 需要至少一个虚函数 }; class Derived1 : public Base {}; class Derived2 : public Base {}; int main() { Base* b = new Derived1(); // typeid:获取类型信息 cout << "Type of b: " << typeid(b).name() << endl; // Base* cout << "Type of *b: " << typeid(*b).name() << endl; // Derived1 // dynamic_cast:安全向下转型 Derived1* d1 = dynamic_cast<Derived1*>(b); if (d1) { cout << "Successfully cast to Derived1" << endl; } Derived2* d2 = dynamic_cast<Derived2*>(b); if (!d2) { cout << "Cannot cast to Derived2" << endl; } // 引用类型的dynamic_cast失败时抛出异常 try { Derived2& r2 = dynamic_cast<Derived2&>(*b); } catch (bad_cast& e) { cout << "Cast failed: " << e.what() << endl; } delete b; return 0; }
#include <iostream> using namespace std; class Document { public: virtual Document* clone() const { return new Document(*this); } virtual void print() const { cout << "Document" << endl; } virtual ~Document() = default; }; class PDF : public Document { public: PDF* clone() const override { // 协变返回类型 return new PDF(*this); } void print() const override { cout << "PDF Document" << endl; } }; class Word : public Document { public: Word* clone() const override { return new Word(*this); } void print() const override { cout << "Word Document" << endl; } }; int main() { Document* doc1 = new PDF(); Document* doc2 = new Word(); Document* copy1 = doc1->clone(); // 实际是PDF* Document* copy2 = doc2->clone(); // 实际是Word* copy1->print(); // PDF Document copy2->print(); // Word Document delete doc1; delete doc2; delete copy1; delete copy2; return 0; }
本章我们学习了:
基础练习:
1. 设计一个图形类层次结构:基类Shape,派生类Circle、Rectangle、Triangle,都实现getArea()和draw()方法
2. 创建一个抽象类Employee,派生出SalariedEmployee和HourlyEmployee,实现不同的工资计算方式
3. 解释为什么基类析构函数应该是虚函数,举例说明
4. 使用多重继承设计一个类,同时实现IPrintable和ISerializable接口
进阶练习:
5. 实现一个游戏角色系统:基类GameCharacter,派生类Player、NPC、Enemy,使用多态实现不同的行为
6. 设计一个文档管理系统,支持多种文档格式(PDF、Word、Excel),使用工厂模式创建对象
7. 实现一个事件处理系统,使用观察者模式,基类Observer,派生类ConcreteObserver
思考题:
8. 比较静态多态(模板)和动态多态(虚函数)的优缺点
9. 虚函数表是如何实现的?研究vtable的布局
10. 什么时候应该使用纯虚函数,什么时候使用普通虚函数?
练习1参考:
class Shape { public: virtual double getArea() const = 0; virtual void draw() const = 0; virtual ~Shape() = default; }; class Circle : public Shape { private: double radius; public: Circle(double r) : radius(r) {} double getArea() const override { return 3.14159 * radius * radius; } void draw() const override { cout << "Drawing circle" << endl; } };
练习2参考:
class Employee { protected: string name; int id; public: Employee(string n, int i) : name(n), id(i) {} virtual double calculatePay() const = 0; virtual ~Employee() = default; }; class SalariedEmployee : public Employee { private: double monthlySalary; public: SalariedEmployee(string n, int i, double s) : Employee(n, i), monthlySalary(s) {} double calculatePay() const override { return monthlySalary; } }; class HourlyEmployee : public Employee { private: double hourlyRate; int hoursWorked; public: HourlyEmployee(string n, int i, double r, int h) : Employee(n, i), hourlyRate(r), hoursWorked(h) {} double calculatePay() const override { return hourlyRate * hoursWorked; } };
继续学习:第七章 运算符重载