Skip to content

Ch 21: 继承和多态

  • 深入理解 Python 和 C++ 继承的本质差异
  • 掌握虚函数和运行时多态的机制
  • 理解纯虚函数和抽象类的设计意义
  • 学会设计清晰的类层次结构
  • 掌握虚析构函数的重要性和菱形继承问题
# Python - 简单直接的继承
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
raise NotImplementedError("Subclasses must implement speak()")
class Dog(Animal):
def speak(self):
return f"{self.name} says woof!"
class Cat(Animal):
def speak(self):
return f"{self.name} says meow!"
# 使用
d = Dog("Buddy")
print(d.speak()) # Buddy says woof!
# 多态 - 运行时确定
def make_speak(animal):
print(animal.speak())
make_speak(Dog("Rex")) # Rex says woof!
make_speak(Cat("Whiskers")) # Whiskers says meow!
# Python - 方法在运行时查找
class Animal:
pass
class Dog(Animal):
pass
# 可以在运行时添加方法
def bark(self):
return "woof!"
Dog.speak = bark # 给 Dog 类添加方法
d = Dog()
print(d.speak()) # woof!
# C++ 无法做到这种动态性
class A:
def method(self): return "A"
class B(A):
def method(self): return "B"
class C(A):
def method(self): return "C"
class D(B, C):
pass
d = D()
print(d.method()) # B(C++ 的虚函数表是编译时决定的)
# Python 使用 C3 线性化算法
print(D.__mro__) # 显示方法解析顺序
#include <string>
#include <iostream>
// 基类
class Animal {
public:
// 构造函数
Animal(const std::string& name) : name_(name) {}
// 虚函数 - 子类可以覆盖
virtual std::string speak() const {
return "...";
}
// 虚析构函数(重要!)
virtual ~Animal() = default;
protected:
std::string name_;
};
// 派生类
class Dog : public Animal {
public:
Dog(const std::string& name) : Animal(name) {}
// override 说明符(C++11)
std::string speak() const override {
return name_ + " says woof!";
}
};
class Cat : public Animal {
public:
Cat(const std::string& name) : Animal(name) {}
std::string speak() const override {
return name_ + " says meow!";
}
};
int main() {
Dog d("Buddy");
Cat c("Whiskers");
std::cout << d.speak() << "\n"; // Buddy says woof!
std::cout << c.speak() << "\n"; // Whiskers says meow!
// 多态:通过基类引用调用派生类实现
Animal& ref = d;
std::cout << ref.speak() << "\n"; // Buddy says woof!
// 基类指针
Animal* p = &c;
std::cout << p->speak() << "\n"; // Whiskers says meow!
return 0;
}
#include <string>
#include <iostream>
// public 继承 - 保持成员的访问级别
class Base {
public:
int public_data;
protected:
int protected_data;
private:
int private_data; // 派生类不能直接访问
};
class PublicDerived : public Base {
// public_data 保持 public
// protected_data 保持 protected
// private_data 不可访问
void access() {
public_data = 1; // OK
protected_data = 2; // OK
// private_data = 3; // ❌ 编译错误
}
};
// protected 继承 - public 成员变为 protected
class ProtectedDerived : protected Base {
void access() {
public_data = 1; // OK(变为 protected)
protected_data = 2; // OK
}
};
// private 继承 - 所有成员变为 private
class PrivateDerived : private Base {
void access() {
public_data = 1; // OK(变为 private)
protected_data = 2; // OK(变为 private)
}
};
# Python 没有访问控制修饰符(只有约定)
class Base:
public_data = 1
_protected_data = 2 # 约定受保护,但仍可访问
__private_data = 3 # 名称改写,但仍可访问
class Derived(Base):
def access(self):
print(self.public_data) # 可访问
print(self._protected_data) # 可访问(约定不访问)
print(self._Base__private_data) # 可访问,但不推荐
#include <iostream>
#include <string>
class Base {
public:
// 虚函数 - 通过 vtable(虚函数表)实现多态
virtual std::string identify() const {
return "Base";
}
// 非虚函数 - 静态绑定,编译时确定
std::string identify_nonvirtual() const {
return "Base (non-virtual)";
}
virtual ~Base() = default;
};
class Derived : public Base {
public:
std::string identify() const override {
return "Derived";
}
std::string identify_nonvirtual() const {
return "Derived (non-virtual)";
}
};
int main() {
Derived d;
// 静态类型和动态类型
Derived* dp = &d; // 静态类型 = Derived*
Base* bp = &d; // 静态类型 = Base*,动态类型 = Derived*
// 虚函数 - 运行时动态分派
std::cout << dp->identify() << "\n"; // Derived(运行时确定)
std::cout << bp->identify() << "\n"; // Derived(通过 vtable)
// 非虚函数 - 编译时静态分派
std::cout << dp->identify_nonvirtual() << "\n"; // Derived (non-virtual)
std::cout << bp->identify_nonvirtual() << "\n"; // Base (non-virtual)
// 引用的情况
Base& br = d;
std::cout << br.identify() << "\n"; // Derived(多态)
return 0;
}
对象布局:
┌─────────────────────────┐
│ Base vptr (指向 vtable) │
├─────────────────────────┤
│ 基类成员 │
└─────────────────────────┘
vtable:
┌─────────────────┐
│ Base::identify │ ← Base 的实现
│ ~Base() │
└─────────────────┘
Derived 对象:
┌─────────────────────────┐
│ Base vptr (指向 Derived vtable)
├─────────────────────────┤
│ 基类成员 │
├─────────────────────────┤
│ Derived 额外成员 │
└─────────────────────────┘
Derived vtable:
┌─────────────────┐
│ Derived::identify│ ← 覆盖了 Base 的实现
│ ~Base() │
└─────────────────┘
#include <iostream>
#include <string>
class Base {
public:
virtual void foo(int x) const {
std::cout << "Base::foo(int)\n";
}
virtual void bar() const {
std::cout << "Base::bar()\n";
}
};
class Derived : public Base {
public:
// ✅ 正确:签名匹配
void foo(int x) const override {
std::cout << "Derived::foo(int)\n";
}
// ✅ 正确:添加 const 也算覆盖
void bar() const override {
std::cout << "Derived::bar()\n";
}
// ❌ 错误:签名不匹配
// void foo(double x) const override { } // 基类没有这个签名
// ❌ 错误:非虚函数不能 override
// void baz() override { } // 基类没有 baz() 虚函数
};
int main() {
Derived d;
d.foo(42); // Derived::foo(int)
d.bar(); // Derived::bar()
return 0;
}
// 禁止进一步重写
class Base {
public:
virtual void foo() const {
std::cout << "Base::foo()\n";
}
};
class Middle : public Base {
public:
void foo() const override { // OK,可以重写
std::cout << "Middle::foo()\n";
}
};
class Final : public Middle {
public:
// ❌ 错误:foo() 在 Middle 中已经是 final
// void foo() const override { }
};
// 或者直接让函数 final
class A {
public:
virtual void method() const final {
// 禁止子类重写这个方法
}
};
// 类 final(C++17)
class B final : public A {
// ❌ 错误:B 不能被继承
};
#include <iostream>
#include <string>
#include <vector>
// 抽象基类 - 包含纯虚函数
class Shape {
public:
// 纯虚函数 = 0 使类成为抽象类
virtual double area() const = 0;
virtual double perimeter() const = 0;
// 抽象类也可以有具体函数
void print() const {
std::cout << "Area: " << area() << "\n";
}
virtual ~Shape() = default;
};
class Rectangle : public Shape {
public:
Rectangle(double w, double h) : w_(w), h_(h) {}
double area() const override {
return w_ * h_;
}
double perimeter() const override {
return 2 * (w_ + h_);
}
private:
double w_, h_;
};
class Circle : public Shape {
public:
explicit Circle(double r) : r_(r) {}
double area() const override {
return 3.14159 * r_ * r_;
}
double perimeter() const override {
return 2 * 3.14159 * r_;
}
private:
double r_;
};
int main() {
// ❌ 错误:不能实例化抽象类
// Shape s;
Rectangle r(3, 4);
Circle c(1);
std::cout << "Rectangle area: " << r.area() << "\n";
std::cout << "Circle area: " << c.area() << "\n";
// 多态:存储在抽象类指针容器中
std::vector<Shape*> shapes = {&r, &c};
double total_area = 0;
for (const Shape* s : shapes) {
total_area += s->area();
}
std::cout << "Total area: " << total_area << "\n";
return 0;
}
#include <string>
#include <iostream>
// 接口 = 纯虚函数 + virtual 析构函数
class Printable {
public:
virtual void print(std::ostream& os) const = 0;
virtual ~Printable() = default;
};
class Serializable {
public:
virtual std::string serialize() const = 0;
virtual ~Serializable() = default;
};
class Data : public Printable, public Serializable {
public:
Data(const std::string& content) : content_(content) {}
void print(std::ostream& os) const override {
os << content_;
}
std::string serialize() const override {
return content_;
}
private:
std::string content_;
};
int main() {
Data d("Hello, World!");
Printable* p = &d;
Serializable* s = &d;
d.print(std::cout);
std::cout << "\n" << s->serialize() << "\n";
return 0;
}
#include <iostream>
#include <string>
#include <vector>
class Animal {
public:
virtual std::string speak() const = 0;
virtual ~Animal() = default;
};
class Dog : public Animal {
public:
std::string speak() const override {
return "Woof!";
}
};
class Cat : public Animal {
public:
std::string speak() const override {
return "Meow!";
}
};
// 接受抽象类引用(推荐)
void make_speak(const Animal& animal) {
std::cout << animal.speak() << "\n";
}
// 接受抽象类指针(当需要可选时)
bool feed(Animal* animal) {
if (!animal) return false;
std::cout << "Feeding " << animal->speak() << "\n";
return true;
}
// 返回抽象类指针(工厂模式)
Animal* create_animal(const std::string& type) {
if (type == "dog") return new Dog();
if (type == "cat") return new Cat();
return nullptr;
}
// 返回智能指针(现代 C++)
#include <memory>
std::unique_ptr<Animal> create_dog() {
return std::make_unique<Dog>();
}
int main() {
Dog d;
make_speak(d); // 多态
feed(&d); // OK
feed(nullptr); // 安全返回 false
auto animal = create_animal("cat");
if (animal) {
std::cout << animal->speak() << "\n";
}
auto dog = create_dog();
make_speak(*dog);
return 0;
}
#include <iostream>
// ❌ 错误的设计:非虚析构函数
class Base {
public:
Base() { std::cout << "Base constructed\n"; }
~Base() { std::cout << "Base destructed\n"; } // 非虚!
};
class Derived : public Base {
public:
Derived() { std::cout << "Derived constructed\n"; }
~Derived() { std::cout << "Derived destructed\n"; }
};
int main() {
Base* p = new Derived();
// Derived constructed
// Base constructed
delete p;
// Base destructed ← 危险!Derived 析构函数未被调用!
// 资源泄漏!
return 0;
}
#include <iostream>
// ✅ 正确:虚析构函数
class Base {
public:
Base() { std::cout << "Base constructed\n"; }
virtual ~Base() { std::cout << "Base destructed\n"; }
};
class Derived : public Base {
public:
Derived() { std::cout << "Derived constructed\n"; }
~Derived() { std::cout << "Derived destructed\n"; }
};
int main() {
Base* p = new Derived();
// Derived constructed
// Base constructed
delete p;
// Derived destructed ← 正确!先调用派生类析构函数
// Base destructed
return 0;
}
// 只要类可能作为基类,就声明虚析构函数
class Base {
public:
virtual ~Base() = default; // 最简单的方式
};
// 抽象基类也需要虚析构函数
class AbstractBase {
public:
virtual void pure_virtual() = 0;
virtual ~AbstractBase() = default; // 必须!
};
#include <iostream>
#include <string>
class Printable {
public:
virtual void print(std::ostream& os) const = 0;
virtual ~Printable() = default;
};
class Serializable {
public:
virtual std::string serialize() const = 0;
virtual ~Serializable() = default;
};
class Document : public Printable, public Serializable {
public:
Document(const std::string& content) : content_(content) {}
void print(std::ostream& os) const override {
os << content_;
}
std::string serialize() const override {
return content_;
}
private:
std::string content_;
};
int main() {
Document doc("Hello");
Printable* p = &doc;
Serializable* s = &doc;
doc.print(std::cout);
std::cout << "\n" << s->serialize() << "\n";
return 0;
}
#include <iostream>
// Base
// / \
// A B
// \ /
// C
class Base {
public:
int data = 42;
virtual ~Base() = default;
};
// 普通继承:A 和 B 各有一份 Base 子对象
class A : public Base {};
class B : public Base {};
class C : public A, public B {
// C 有两份 data!
};
int main() {
C c;
// c.data; // ❌ 编译错误!data 不明确(两份)
c.A::data = 1; // 明确指定
c.B::data = 2;
std::cout << "A::data = " << c.A::data << "\n";
std::cout << "B::data = " << c.B::data << "\n";
return 0;
}
#include <iostream>
// Base
// / \
// A B
// \ /
// C
class Base {
public:
int data = 42;
virtual ~Base() = default;
};
// 虚继承:共享同一个 Base 子对象
class A : virtual public Base {};
class B : virtual public Base {};
class C : public A, public B {
// C 只有一份 Base 子对象
};
int main() {
C c;
c.data = 100; // OK!只有一份 data
c.A::data = 1; // 也可以,但效果相同(同一份)
c.B::data = 2; // 覆盖上面的
std::cout << "data = " << c.data << "\n"; // 2
return 0;
}
#include <iostream>
#include <string>
class Base {
public:
Base(const std::string& name) : name_(name) {
std::cout << "Base(" << name_ << ")\n";
}
protected:
std::string name_;
};
class A : virtual public Base {
public:
A() : Base("A") {} // 即使不直接使用,也需要调用
};
class B : virtual public Base {
public:
B() : Base("B") {} // 即使不直接使用,也需要调用
};
class C : public A, public B {
public:
// C 的构造函数需要直接调用虚基类构造函数
C() : Base("C") {} // 只有 C 需要调用
};
int main() {
std::cout << "Creating C:\n";
C c; // 只调用 Base("C") 一次
// Base(C)
// A
// B
return 0;
}
#include <iostream>
#include <vector>
#include <memory>
#include <cmath>
// 抽象基类:可绘制图形
class Drawable {
public:
virtual void draw(std::ostream& os) const = 0;
virtual double area() const = 0;
virtual std::string name() const = 0;
virtual ~Drawable() = default;
};
// 抽象基类:可移动
class Transformable {
public:
virtual void move(double dx, double dy) = 0;
virtual void scale(double factor) = 0;
virtual ~Transformable() = default;
};
// 图形:同时继承多个接口
class Shape : public Drawable, public Transformable {
public:
Shape(double x, double y) : x_(x), y_(y) {}
void move(double dx, double dy) override {
x_ += dx;
y_ += dy;
}
std::string position() const {
return "(" + std::to_string(x_) + ", " + std::to_string(y_) + ")";
}
protected:
double x_;
double y_;
};
class Circle : public Shape {
public:
Circle(double x, double y, double r) : Shape(x, y), radius_(r) {}
double area() const override {
return 3.14159 * radius_ * radius_;
}
void draw(std::ostream& os) const override {
os << "Circle at " << position()
<< " with radius " << radius_
<< " (area=" << area() << ")";
}
std::string name() const override { return "Circle"; }
void scale(double factor) override {
radius_ *= factor;
}
private:
double radius_;
};
class Rectangle : public Shape {
public:
Rectangle(double x, double y, double w, double h)
: Shape(x, y), width_(w), height_(h) {}
double area() const override {
return width_ * height_;
}
void draw(std::ostream& os) const override {
os << "Rectangle at " << position()
<< " " << width_ << "x" << height_
<< " (area=" << area() << ")";
}
std::string name() const override { return "Rectangle"; }
void scale(double factor) override {
width_ *= factor;
height_ *= factor;
}
private:
double width_;
double height_;
};
int main() {
std::vector<std::unique_ptr<Drawable>> shapes;
shapes.push_back(std::make_unique<Circle>(0, 0, 5));
shapes.push_back(std::make_unique<Rectangle>(10, 10, 4, 3));
shapes.push_back(std::make_unique<Circle>(3, 3, 2));
std::cout << "=== All Shapes ===\n";
for (const auto& s : shapes) {
s->draw(std::cout);
std::cout << "\n";
}
// 计算总面积
double total_area = 0;
for (const auto& s : shapes) {
total_area += s->area();
}
std::cout << "\nTotal area: " << total_area << "\n";
// 移动所有图形
std::cout << "\n=== After Moving ===\n";
for (auto& s : shapes) {
// 向下转型为 Transformable
if (auto* t = dynamic_cast<Transformable*>(s.get())) {
t->move(5, 5);
t->scale(1.5);
}
s->draw(std::cout);
std::cout << "\n";
}
return 0;
}
概念说明
virtual虚函数,运行时多态
override明确覆盖基类虚函数(编译时检查)
final禁止进一步重写(C++11)
= 0纯虚函数,类成为抽象类
virtual ~Base()虚析构函数,确保派生类析构函数被调用
多重继承从多个基类继承
虚继承 virtual解决菱形继承问题

设计原则:

  • 作为基类的类,声明虚析构函数
  • 优先使用 override 说明符
  • 接口类只有纯虚函数
  • 多重继承慎用,优先考虑组合

下章预告:ch22 学习运算符重载,实现自定义类型的运算符行为。