

多态性(Polymorphism)是面向对象编程中的一个重要概念,它允许同一名称的实体在不同的场景下表现出不同的行为。简单来说,就是 "一个接口,多种实现"。
C++ 中的多态主要分为两类:

C++ 中实现多态的机制主要有以下几种:
运算符重载是 C++ 的重要特性,它允许我们为自定义类型重新定义运算符的行为,使代码更直观、更易读。
运算符重载需要遵循以下规则:
.、.*、::、? :、sizeof。当运算符重载为类的成员函数时,左操作数是当前对象,右操作数是函数参数。
下面是一个复数类的例子,展示如何将+、-、*和<<运算符重载为成员函数:
#include <iostream>
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);
}
// 运算符*重载为成员函数
Complex operator*(const Complex& other) const {
// (a+bi)*(c+di) = (ac-bd) + (ad+bc)i
return Complex(
real * other.real - imag * other.imag,
real * other.imag + imag * other.real
);
}
// 为了能访问私有成员,声明<<运算符为友元
friend ostream& operator<<(ostream& os, const Complex& c);
};
// 8.2.3 运算符重载为非成员函数
// <<运算符重载为非成员函数
ostream& operator<<(ostream& os, const Complex& c) {
os << c.real;
if (c.imag >= 0) os << "+";
os << c.imag << "i";
return os;
}
int main() {
Complex c1(3, 4), c2(1, 2);
Complex c3 = c1 + c2;
Complex c4 = c1 - c2;
Complex c5 = c1 * c2;
cout << "c1 = " << c1 << endl;
cout << "c2 = " << c2 << endl;
cout << "c1 + c2 = " << c3 << endl;
cout << "c1 - c2 = " << c4 << endl;
cout << "c1 * c2 = " << c5 << endl;
return 0;
}
在上面的例子中,+、-、*运算符被重载为Complex类的成员函数。当我们写c1 + c2时,编译器会将其转换为c1.operator+(c2)的调用。
成员函数形式的运算符重载语法如下:
返回类型 operator运算符(参数列表) {
// 实现代码
} 有些运算符更适合重载为非成员函数,特别是当左操作数不是类的对象时,如输入输出运算符<<和>>。
非成员函数形式的运算符重载语法如下:
返回类型 operator运算符(参数列表) {
// 实现代码
}如果需要访问类的私有成员,非成员运算符重载函数通常会被声明为类的友元。
在上面的复数类例子中,<<运算符被重载为非成员函数,并声明为Complex类的友元,以便访问其私有成员real和imag。
虚函数是实现动态多态的核心机制,它允许派生类重写基类的函数,并在运行时根据对象的实际类型调用相应的函数。
虚函数的声明方式是在基类的函数声明前加上virtual关键字。派生类可以重写该函数,重写时可以省略virtual关键字,但建议加上以提高可读性。
下面是一个展示虚函数用法的例子:
#include <iostream>
using namespace std;
// 基类:形状
class Shape {
public:
// 虚函数:计算面积
virtual double area() const {
cout << "Shape::area() called" << endl;
return 0;
}
// 虚函数:计算周长
virtual double perimeter() const {
cout << "Shape::perimeter() called" << endl;
return 0;
}
// 普通函数:打印形状信息
void printInfo() const {
cout << "This is a shape." << endl;
}
};
// 派生类:圆形
class Circle : public Shape {
private:
double radius; // 半径
public:
// 构造函数
Circle(double r) : radius(r) {}
// 重写基类的虚函数:计算面积
virtual double area() const override {
cout << "Circle::area() called" << endl;
return 3.14159 * radius * radius;
}
// 重写基类的虚函数:计算周长
virtual double perimeter() const override {
cout << "Circle::perimeter() called" << endl;
return 2 * 3.14159 * radius;
}
};
// 派生类:矩形
class Rectangle : public Shape {
private:
double length; // 长度
double width; // 宽度
public:
// 构造函数
Rectangle(double l, double w) : length(l), width(w) {}
// 重写基类的虚函数:计算面积
virtual double area() const override {
cout << "Rectangle::area() called" << endl;
return length * width;
}
// 重写基类的虚函数:计算周长
virtual double perimeter() const override {
cout << "Rectangle::perimeter() called" << endl;
return 2 * (length + width);
}
// 新增函数:获取长宽比
double aspectRatio() const {
return length / width;
}
};
// 函数:打印形状的面积和周长
void printShapeInfo(const Shape& shape) {
cout << "Area: " << shape.area() << endl;
cout << "Perimeter: " << shape.perimeter() << endl;
shape.printInfo(); // 调用的是基类的普通函数
cout << "-------------------------" << endl;
}
int main() {
// 创建基类对象
Shape shape;
// 创建派生类对象
Circle circle(5.0);
Rectangle rectangle(4.0, 6.0);
// 直接调用函数
cout << "直接调用函数:" << endl;
shape.area();
circle.area();
rectangle.area();
cout << "-------------------------" << endl;
// 通过基类指针调用函数
cout << "通过基类指针调用函数:" << endl;
Shape* shapePtr1 = &shape;
Shape* shapePtr2 = &circle;
Shape* shapePtr3 = &rectangle;
shapePtr1->area(); // 调用Shape的area()
shapePtr2->area(); // 调用Circle的area()
shapePtr3->area(); // 调用Rectangle的area()
cout << "-------------------------" << endl;
// 通过基类引用调用函数
cout << "通过基类引用调用函数:" << endl;
printShapeInfo(shape);
printShapeInfo(circle);
printShapeInfo(rectangle);
return 0;
}
上面的代码展示了虚函数的核心特性:当通过基类指针或引用调用虚函数时,会根据指针或引用所指向的对象的实际类型来调用相应的函数版本,而不是指针或引用本身的类型。
C++11 引入了override关键字,用于显式指定派生类的函数是重写基类的虚函数,这样可以在编译时检测出潜在的错误,如函数签名不匹配等问题。
析构函数也可以声明为虚函数,称为虚析构函数。当基类指针指向派生类对象并通过基类指针删除对象时,虚析构函数确保派生类的析构函数会被调用,从而正确释放资源。
下面是一个展示虚析构函数重要性的例子:
#include <iostream>
#include <string>
using namespace std;
// 基类
class Base {
public:
// 构造函数
Base() {
cout << "Base constructor called" << endl;
}
// 虚析构函数
virtual ~Base() {
cout << "Base destructor called" << endl;
}
};
// 派生类
class Derived : public Base {
private:
string* data; // 动态分配的资源
public:
// 构造函数
Derived(const string& s) {
cout << "Derived constructor called" << endl;
data = new string(s); // 分配资源
}
// 析构函数
~Derived() override {
cout << "Derived destructor called" << endl;
delete data; // 释放资源
}
};
int main() {
cout << "创建Base对象:" << endl;
Base* baseObj = new Base();
delete baseObj;
cout << endl;
cout << "创建Derived对象,用Derived指针指向:" << endl;
Derived* derivedObj1 = new Derived("Test string 1");
delete derivedObj1;
cout << endl;
cout << "创建Derived对象,用Base指针指向:" << endl;
Base* derivedObj2 = new Derived("Test string 2");
delete derivedObj2; // 如果Base的析构函数不是虚函数,这里只会调用Base的析构函数
return 0;
}
如果基类的析构函数不是虚函数,当通过基类指针删除派生类对象时,只会调用基类的析构函数,而不会调用派生类的析构函数,可能导致资源泄漏。因此,通常建议将基类的析构函数声明为虚函数。
纯虚函数是一种特殊的虚函数,它在基类中声明但没有实现,其声明方式是在函数原型后加上= 0。
纯虚函数的语法如下:
virtual 返回类型 函数名(参数列表) const = 0;纯虚函数的作用是为派生类提供一个统一的接口,强制派生类实现该函数。
包含纯虚函数的类称为抽象类。抽象类不能实例化对象,只能作为基类被继承。派生类必须实现抽象类中的所有纯虚函数才能成为非抽象类,否则它仍然是抽象类。
下面是一个展示纯虚函数和抽象类用法的例子:
#include <iostream>
#include <string>
using namespace std;
// 抽象类:图形接口
class Graphic {
public:
// 纯虚函数:绘制图形
virtual void draw() const = 0;
// 纯虚函数:计算面积
virtual double area() const = 0;
// 纯虚函数:获取图形描述
virtual string description() const = 0;
// 普通成员函数
void printInfo() const {
cout << description() << ", Area: " << area() << endl;
}
// 虚析构函数
virtual ~Graphic() = default;
};
// 具体类:圆形
class Circle : public Graphic {
private:
double radius; // 半径
string name; // 名称
public:
// 构造函数
Circle(double r, const string& n) : radius(r), name(n) {}
// 实现纯虚函数:绘制图形
void draw() const override {
cout << "Drawing circle: " << name << endl;
// 实际绘制逻辑...
}
// 实现纯虚函数:计算面积
double area() const override {
return 3.14159 * radius * radius;
}
// 实现纯虚函数:获取图形描述
string description() const override {
return "Circle '" + name + "' (radius: " + to_string(radius) + ")";
}
};
// 具体类:矩形
class Rectangle : public Graphic {
private:
double width; // 宽度
double height; // 高度
string name; // 名称
public:
// 构造函数
Rectangle(double w, double h, const string& n)
: width(w), height(h), name(n) {}
// 实现纯虚函数:绘制图形
void draw() const override {
cout << "Drawing rectangle: " << name << endl;
// 实际绘制逻辑...
}
// 实现纯虚函数:计算面积
double area() const override {
return width * height;
}
// 实现纯虚函数:获取图形描述
string description() const override {
return "Rectangle '" + name + "' (width: " + to_string(width) +
", height: " + to_string(height) + ")";
}
};
// 函数:绘制图形并显示信息
void processGraphic(const Graphic& graphic) {
graphic.draw();
graphic.printInfo();
cout << "-------------------------" << endl;
}
int main() {
// 不能实例化抽象类
// Graphic graphic; // 编译错误:Cannot declare variable 'graphic' to be of abstract type 'Graphic'
// 创建具体类的对象
Circle circle(5.0, "My Circle");
Rectangle rectangle(4.0, 6.0, "My Rectangle");
// 通过基类引用处理不同的图形对象
processGraphic(circle);
processGraphic(rectangle);
// 通过基类指针数组管理不同的图形对象
Graphic* graphics[] = {&circle, &rectangle};
const int numGraphics = sizeof(graphics) / sizeof(graphics[0]);
cout << "Total area of all graphics: ";
double totalArea = 0;
for (int i = 0; i < numGraphics; ++i) {
totalArea += graphics[i]->area();
}
cout << totalArea << endl;
return 0;
}
上面的代码中,Graphic类是一个抽象类,它包含三个纯虚函数:draw()、area()和description()。Circle和Rectangle类继承自Graphic并实现了所有纯虚函数,因此它们是具体类,可以实例化对象。
抽象类的主要作用是定义接口,为一组相关的类提供统一的对外接口,同时强制派生类实现这些接口,保证了接口的一致性。

为了实现变步长梯形积分算法,我们可以设计如下类结构:
Function,包含纯虚函数operator(),用于计算函数值Function,如SinFunction、PolynomialFunction等Integrator,包含计算积分的方法这样的设计利用了多态性,使得积分计算器可以处理任何继承自Function的函数对象。
@startuml
abstract class Function {
+ {abstract} operator()(double x): double
}
class SinFunction {
+ operator()(double x): double
}
class PolynomialFunction {
- coefficients: vector<double>
+ PolynomialFunction(coefficients: vector<double>)
+ operator()(double x): double
}
class Integrator {
- eps: double
+ Integrator(eps: double = 1e-6)
+ integrate(f: Function&, a: double, b: double): double
- trapezoidal(f: Function&, a: double, b: double, n: int): double
}
Function <|-- SinFunction
Function <|-- PolynomialFunction
Integrator --> Function
@enduml
#include <iostream>
#include <cmath>
#include <vector>
#include <iomanip>
using namespace std;
// 抽象基类:函数接口
class Function {
public:
// 纯虚函数:计算函数值
virtual double operator()(double x) const = 0;
// 虚析构函数
virtual ~Function() = default;
};
// 具体函数:正弦函数 f(x) = sin(x)
class SinFunction : public Function {
public:
double operator()(double x) const override {
return sin(x);
}
};
// 具体函数:多项式函数 f(x) = a0 + a1*x + a2*x^2 + ... + an*x^n
class PolynomialFunction : public Function {
private:
vector<double> coefficients; // 多项式系数,coefficients[i] 对应 x^i 的系数
public:
// 构造函数:接受多项式系数
PolynomialFunction(const vector<double>& coeffs) : coefficients(coeffs) {}
// 计算多项式在x处的值
double operator()(double x) const override {
double result = 0.0;
double xPower = 1.0; // x^0 = 1
for (double coeff : coefficients) {
result += coeff * xPower;
xPower *= x; // 计算 x^1, x^2, ..., x^n
}
return result;
}
};
// 具体函数:指数函数 f(x) = e^x
class ExpFunction : public Function {
public:
double operator()(double x) const override {
return exp(x);
}
};
// 积分计算器类
class Integrator {
private:
double eps; // 精度要求
// 梯形法计算积分
// a, b: 积分区间
// n: 区间等分数
double trapezoidal(const Function& f, double a, double b, int n) const {
double h = (b - a) / n; // 步长
double sum = 0.5 * (f(a) + f(b)); // 首末项之和的一半
// 累加中间项
for (int i = 1; i < n; ++i) {
double x = a + i * h;
sum += f(x);
}
return sum * h; // 乘以步长得到积分值
}
public:
// 构造函数:设置精度,默认1e-6
Integrator(double precision = 1e-6) : eps(precision) {}
// 变步长梯形积分算法
// f: 被积函数
// a, b: 积分区间
double integrate(const Function& f, double a, double b) const {
int n = 1; // 初始区间等分数
double T1 = trapezoidal(f, a, b, n); // 初始积分值
while (true) {
n *= 2; // 区间二分
double T2 = trapezoidal(f, a, b, n); // 计算新的积分值
// 判断精度是否满足要求
if (abs(T2 - T1) < eps) {
return T2;
}
T1 = T2; // 更新积分值,继续迭代
}
}
};
int main() {
// 创建积分器,设置精度为1e-8
Integrator integrator(1e-8);
// 测试1:计算 sin(x) 在 [0, π] 上的积分,理论值为 2
SinFunction sinFunc;
double result1 = integrator.integrate(sinFunc, 0, M_PI);
cout << "∫ sin(x) dx from 0 to π = " << fixed << setprecision(6) << result1
<< ", 理论值 = 2.0" << endl;
// 测试2:计算多项式 f(x) = 1 + x + x^2 在 [0, 1] 上的积分,理论值为 1 + 0.5 + 1/3 ≈ 1.833333
vector<double> coeffs = {1.0, 1.0, 1.0}; // 1 + x + x^2
PolynomialFunction polyFunc(coeffs);
double result2 = integrator.integrate(polyFunc, 0, 1);
cout << "∫ (1 + x + x^2) dx from 0 to 1 = " << fixed << setprecision(6) << result2
<< ", 理论值 ≈ 1.833333" << endl;
// 测试3:计算 e^x 在 [0, 1] 上的积分,理论值为 e - 1 ≈ 1.7182818
ExpFunction expFunc;
double result3 = integrator.integrate(expFunc, 0, 1);
cout << "∫ e^x dx from 0 to 1 = " << fixed << setprecision(6) << result3
<< ", 理论值 ≈ 1.718282" << endl;
// 自定义函数测试:计算 f(x) = x^3 在 [0, 2] 上的积分,理论值为 4
class CubeFunction : public Function {
public:
double operator()(double x) const override {
return x * x * x;
}
};
CubeFunction cubeFunc;
double result4 = integrator.integrate(cubeFunc, 0, 2);
cout << "∫ x^3 dx from 0 to 2 = " << fixed << setprecision(6) << result4
<< ", 理论值 = 4.0" << endl;
return 0;
}程序运行结果如下:

结果分析:
Function的函数对象,包括预定义的和用户自定义的函数。Function类并实现operator()即可。我们将利用多态性对个人银行账户管理程序进行改进,支持不同类型的账户(如储蓄账户、支票账户等),每种账户有不同的利息计算方式和手续费规则。
#include <iostream>
#include <string>
#include <vector>
#include <iomanip>
using namespace std;
// 日期类,用于记录交易日期
class Date {
private:
int year, month, day;
public:
Date(int y = 2000, int m = 1, int d = 1) : year(y), month(m), day(d) {}
// 简单的日期输出
string toString() const {
return to_string(year) + "-" +
(month < 10 ? "0" : "") + to_string(month) + "-" +
(day < 10 ? "0" : "") + to_string(day);
}
// 获取当前日期(简化版)
static Date today() {
// 实际应用中应该从系统获取当前日期
return Date(2023, 10, 1);
}
};
// 交易记录类
class Transaction {
private:
Date date; // 交易日期
double amount; // 交易金额
string type; // 交易类型
string note; // 交易备注
public:
Transaction(Date d, double a, const string& t, const string& n)
: date(d), amount(a), type(t), note(n) {}
// 输出交易记录
void print() const {
cout << left << setw(12) << date.toString()
<< setw(10) << type
<< setw(12) << fixed << setprecision(2) << amount
<< note << endl;
}
};
// 银行账户抽象基类
class BankAccount {
protected:
string accountNumber; // 账号
string ownerName; // 账户名
double balance; // 余额
vector<Transaction> transactions; // 交易记录
Date lastInterestDate; // 上次计息日期
public:
// 构造函数
BankAccount(const string& accNum, const string& name, double initialBalance = 0)
: accountNumber(accNum), ownerName(name), balance(initialBalance) {
Date today = Date::today();
lastInterestDate = today;
if (initialBalance > 0) {
transactions.emplace_back(today, initialBalance, "Deposit", "Initial deposit");
}
}
// 析构函数
virtual ~BankAccount() = default;
// 获取账号
string getAccountNumber() const { return accountNumber; }
// 获取账户名
string getOwnerName() const { return ownerName; }
// 获取余额
double getBalance() const { return balance; }
// 存款
virtual void deposit(double amount, const string& note = "") {
if (amount <= 0) {
cout << "Error: Deposit amount must be positive." << endl;
return;
}
balance += amount;
transactions.emplace_back(Date::today(), amount, "Deposit", note);
cout << "Deposit successful. New balance: " << fixed << setprecision(2) << balance << endl;
}
// 取款(纯虚函数,强制派生类实现)
virtual bool withdraw(double amount, const string& note = "") = 0;
// 计算利息(纯虚函数,不同账户类型计算方式不同)
virtual void calculateInterest() = 0;
// 显示账户信息
virtual void displayAccountInfo() const {
cout << "Account Information:" << endl;
cout << "Account Number: " << accountNumber << endl;
cout << "Account Owner: " << ownerName << endl;
cout << "Current Balance: " << fixed << setprecision(2) << balance << endl;
cout << "Account Type: " << getAccountType() << endl;
}
// 显示交易记录
void displayTransactions() const {
cout << "\nTransaction History:" << endl;
cout << left << setw(12) << "Date"
<< setw(10) << "Type"
<< setw(12) << "Amount"
<< "Note" << endl;
cout << string(50, '-') << endl;
for (const auto& trans : transactions) {
trans.print();
}
}
// 获取账户类型(纯虚函数)
virtual string getAccountType() const = 0;
// 显示账户摘要
void printSummary() const {
cout << left << setw(15) << accountNumber
<< setw(20) << ownerName
<< setw(15) << getAccountType()
<< fixed << setprecision(2) << balance << endl;
}
};
// 储蓄账户类
class SavingsAccount : public BankAccount {
private:
double interestRate; // 年利率
double minBalance; // 最低余额要求
public:
// 构造函数
SavingsAccount(const string& accNum, const string& name,
double rate = 0.02, double minBal = 100,
double initialBalance = 0)
: BankAccount(accNum, name, initialBalance),
interestRate(rate), minBalance(minBal) {}
// 取款
bool withdraw(double amount, const string& note = "") override {
if (amount <= 0) {
cout << "Error: Withdrawal amount must be positive." << endl;
return false;
}
// 检查余额是否足够,包括可能的手续费
double needed = amount;
if (balance - amount < minBalance) {
needed += 10; // 低于最低余额,收取10元手续费
cout << "Warning: Withdrawal will result in balance below minimum. $10 fee applies." << endl;
}
if (balance < needed) {
cout << "Error: Insufficient funds for withdrawal." << endl;
return false;
}
balance -= needed;
transactions.emplace_back(Date::today(), -amount, "Withdrawal", note);
if (needed > amount) {
transactions.emplace_back(Date::today(), -10, "Fee", "Below minimum balance");
}
cout << "Withdrawal successful. New balance: " << fixed << setprecision(2) << balance << endl;
return true;
}
// 计算利息(假设每月计算一次利息)
void calculateInterest() override {
Date today = Date::today();
// 简化:假设每月计算一次利息
double interest = balance * interestRate / 12;
if (interest > 0) {
balance += interest;
transactions.emplace_back(today, interest, "Interest", "Monthly interest");
lastInterestDate = today;
cout << "Interest calculated: " << fixed << setprecision(2) << interest
<< ". New balance: " << balance << endl;
}
}
// 获取账户类型
string getAccountType() const override {
return "Savings";
}
// 显示账户信息(重写,增加储蓄账户特有信息)
void displayAccountInfo() const override {
BankAccount::displayAccountInfo();
cout << "Interest Rate: " << fixed << setprecision(2) << (interestRate * 100) << "%" << endl;
cout << "Minimum Balance: " << fixed << setprecision(2) << minBalance << endl;
cout << "Last Interest Date: " << lastInterestDate.toString() << endl;
}
};
// 支票账户类
class CheckingAccount : public BankAccount {
private:
double monthlyFee; // 月费
double transactionFee; // 每笔交易手续费
int freeTransactions; // 每月免费交易次数
int transactionCount; // 当月交易次数
public:
// 构造函数
CheckingAccount(const string& accNum, const string& name,
double fee = 5.0, double transFee = 0.5,
int freeTrans = 10, double initialBalance = 0)
: BankAccount(accNum, name, initialBalance),
monthlyFee(fee), transactionFee(transFee),
freeTransactions(freeTrans), transactionCount(0) {}
// 存款(重写,增加交易计数)
void deposit(double amount, const string& note = "") override {
BankAccount::deposit(amount, note);
transactionCount++;
applyTransactionFees();
}
// 取款
bool withdraw(double amount, const string& note = "") override {
if (amount <= 0) {
cout << "Error: Withdrawal amount must be positive." << endl;
return false;
}
// 计算所需金额,包括可能的手续费
double needed = amount;
if (transactionCount >= freeTransactions) {
needed += transactionFee;
}
if (balance < needed) {
cout << "Error: Insufficient funds for withdrawal." << endl;
return false;
}
balance -= needed;
transactions.emplace_back(Date::today(), -amount, "Withdrawal", note);
transactionCount++;
// 如果超过免费交易次数,记录手续费
if (transactionCount > freeTransactions) {
transactions.emplace_back(Date::today(), -transactionFee, "Fee", "Transaction fee");
}
cout << "Withdrawal successful. New balance: " << fixed << setprecision(2) << balance << endl;
return true;
}
// 计算利息(支票账户利息较低)
void calculateInterest() override {
Date today = Date::today();
// 支票账户利息较低,假设年利率0.5%
double interestRate = 0.005;
double interest = balance * interestRate / 12;
if (interest > 0) {
balance += interest;
transactions.emplace_back(today, interest, "Interest", "Monthly interest");
// 扣除月费
if (monthlyFee > 0 && balance >= monthlyFee) {
balance -= monthlyFee;
transactions.emplace_back(today, -monthlyFee, "Fee", "Monthly service fee");
}
lastInterestDate = today;
transactionCount = 0; // 重置每月交易计数
cout << "Interest calculated: " << fixed << setprecision(2) << interest
<< ". Monthly fee: " << monthlyFee
<< ". New balance: " << balance << endl;
}
}
// 获取账户类型
string getAccountType() const override {
return "Checking";
}
// 显示账户信息(重写,增加支票账户特有信息)
void displayAccountInfo() const override {
BankAccount::displayAccountInfo();
cout << "Monthly Fee: " << fixed << setprecision(2) << monthlyFee << endl;
cout << "Transaction Fee: " << fixed << setprecision(2) << transactionFee << endl;
cout << "Free Transactions: " << freeTransactions << endl;
cout << "Transactions this month: " << transactionCount << endl;
cout << "Last Statement Date: " << lastInterestDate.toString() << endl;
}
private:
// 应用交易手续费
void applyTransactionFees() {
if (transactionCount > freeTransactions) {
balance -= transactionFee;
transactions.emplace_back(Date::today(), -transactionFee, "Fee", "Transaction fee");
cout << "Transaction fee applied: " << fixed << setprecision(2) << transactionFee << endl;
}
}
};
// 银行类,管理多个账户
class Bank {
private:
string bankName;
vector<BankAccount*> accounts; // 账户集合
public:
// 构造函数
Bank(const string& name) : bankName(name) {}
// 析构函数,释放账户
~Bank() {
for (auto account : accounts) {
delete account;
}
}
// 添加账户
void addAccount(BankAccount* account) {
if (account) {
accounts.push_back(account);
cout << "Account " << account->getAccountNumber() << " added to " << bankName << endl;
}
}
// 查找账户
BankAccount* findAccount(const string& accountNumber) const {
for (auto account : accounts) {
if (account->getAccountNumber() == accountNumber) {
return account;
}
}
return nullptr;
}
// 显示所有账户摘要
void displayAllAccounts() const {
cout << "\n" << bankName << " Account Summary:" << endl;
cout << string(60, '-') << endl;
cout << left << setw(15) << "Account Number"
<< setw(20) << "Account Owner"
<< setw(15) << "Account Type"
<< "Balance" << endl;
cout << string(60, '-') << endl;
for (auto account : accounts) {
account->printSummary();
}
}
// 对所有账户计算利息
void calculateAllInterest() {
cout << "\nCalculating interest for all accounts..." << endl;
for (auto account : accounts) {
cout << "\nProcessing account " << account->getAccountNumber() << ":" << endl;
account->calculateInterest();
}
}
};
// 主函数
int main() {
// 创建银行
Bank myBank("City Bank");
// 创建不同类型的账户并添加到银行
BankAccount* savings = new SavingsAccount("SA12345", "John Doe", 0.025, 500, 1000);
BankAccount* checking = new CheckingAccount("CA67890", "Jane Smith", 8.0, 0.75, 15, 500);
BankAccount* savings2 = new SavingsAccount("SA54321", "Bob Johnson", 0.02, 300, 2000);
myBank.addAccount(savings);
myBank.addAccount(checking);
myBank.addAccount(savings2);
// 显示所有账户摘要
myBank.displayAllAccounts();
// 进行一些交易
cout << "\n=== Performing transactions ===" << endl;
// John 的储蓄账户存款和取款
savings->deposit(500, "Salary deposit");
savings->withdraw(300, "Cash withdrawal");
// Jane 的支票账户交易
checking->deposit(1500, "Monthly salary");
checking->withdraw(200, "Grocery shopping");
checking->withdraw(100, "Gas");
checking->deposit(300, "Freelance payment");
// 显示Jane账户的详细信息和交易记录
cout << "\n=== Jane's account details ===" << endl;
checking->displayAccountInfo();
checking->displayTransactions();
// 计算所有账户的利息
myBank.calculateAllInterest();
// 显示更新后的所有账户摘要
myBank.displayAllAccounts();
// Bob 的储蓄账户进行一些操作
cout << "\n=== Bob's transactions ===" << endl;
savings2->withdraw(1000, "Home improvement");
savings2->deposit(2000, "Bonus");
savings2->displayAccountInfo();
return 0;
}
这个改进后的银行账户管理程序利用了多态性,主要特点包括:
BankAccount抽象基类,包含纯虚函数withdraw()、calculateInterest()和getAccountType()SavingsAccount和CheckingAccount,它们各自实现了基类的纯虚函数Bank类管理多个账户,通过基类指针BankAccount*可以统一处理不同类型的账户这种设计的优点是:
BankAccount并实现纯虚函数在 C++ 中,类型可以分为多态类型和非多态类型:
下面的代码展示了多态类型和非多态类型的区别:
#include <iostream>
#include <typeinfo>
using namespace std;
// 非多态基类
class NonPolymorphicBase {
public:
void print() const {
cout << "NonPolymorphicBase::print()" << endl;
}
};
// 非多态派生类
class NonPolymorphicDerived : public NonPolymorphicBase {
public:
void print() const {
cout << "NonPolymorphicDerived::print()" << endl;
}
};
// 多态基类
class PolymorphicBase {
public:
virtual void print() const {
cout << "PolymorphicBase::print()" << endl;
}
// 虚析构函数
virtual ~PolymorphicBase() = default;
};
// 多态派生类
class PolymorphicDerived : public PolymorphicBase {
public:
void print() const override {
cout << "PolymorphicDerived::print()" << endl;
}
};
// 函数模板,打印对象类型和调用print方法
template <typename T>
void processObject(T& obj) {
cout << "Type: " << typeid(obj).name() << endl;
obj.print();
cout << "-------------------------" << endl;
}
int main() {
// 非多态类型示例
cout << "=== Non-polymorphic types ===" << endl;
NonPolymorphicBase npBase;
NonPolymorphicDerived npDerived;
processObject(npBase);
processObject(npDerived);
// 通过基类指针指向派生类对象(非多态)
NonPolymorphicBase* npPtr = &npDerived;
cout << "Non-polymorphic via base pointer:" << endl;
cout << "Type: " << typeid(*npPtr).name() << endl; // 仍然是基类类型
npPtr->print(); // 调用基类的print()
cout << "-------------------------" << endl;
// 多态类型示例
cout << "\n=== Polymorphic types ===" << endl;
PolymorphicBase pBase;
PolymorphicDerived pDerived;
processObject(pBase);
processObject(pDerived);
// 通过基类指针指向派生类对象(多态)
PolymorphicBase* pPtr = &pDerived;
cout << "Polymorphic via base pointer:" << endl;
cout << "Type: " << typeid(*pPtr).name() << endl; // 正确识别为派生类类型
pPtr->print(); // 调用派生类的print()
cout << "-------------------------" << endl;
return 0;
}
运行结果显示:
typeid仍然返回基类类型,调用的也是基类的方法。typeid能够正确识别出实际的派生类类型,调用的也是派生类的方法。运行时类型识别(RTTI,Run-Time Type Information)是 C++ 提供的一种机制,允许在程序运行时获取对象的类型信息。主要通过以下两个操作符实现:
dynamic_cast:用于在继承层次中进行安全的类型转换typeid:用于获取对象的类型信息下面是展示 RTTI 用法的示例:
#include <iostream>
#include <typeinfo>
#include <string>
using namespace std;
// 基类:动物
class Animal {
protected:
string name;
public:
Animal(const string& n) : name(n) {}
virtual void makeSound() const = 0; // 纯虚函数
virtual void move() const {
cout << name << " is moving." << endl;
}
virtual ~Animal() = default;
string getName() const { return name; }
};
// 派生类:狗
class Dog : public Animal {
private:
string breed;
public:
Dog(const string& n, const string& b) : Animal(n), breed(b) {}
void makeSound() const override {
cout << name << " barks: Woof! Woof!" << endl;
}
void move() const override {
cout << name << " is running." << endl;
}
// 狗特有的方法
void fetch() const {
cout << name << " is fetching the ball." << endl;
}
string getBreed() const { return breed; }
};
// 派生类:猫
class Cat : public Animal {
public:
Cat(const string& n) : Animal(n) {}
void makeSound() const override {
cout << name << " meows: Meow! Meow!" << endl;
}
void move() const override {
cout << name << " is walking silently." << endl;
}
// 猫特有的方法
void climbTree() const {
cout << name << " is climbing the tree." << endl;
}
};
// 派生类:鸟
class Bird : public Animal {
public:
Bird(const string& n) : Animal(n) {}
void makeSound() const override {
cout << name << " sings: Chirp! Chirp!" << endl;
}
void move() const override {
cout << name << " is flying." << endl;
}
// 鸟特有的方法
void flyHigh() const {
cout << name << " is flying high in the sky." << endl;
}
};
// 处理动物的函数
void processAnimal(const Animal& animal) {
cout << "\nProcessing " << animal.getName() << ":" << endl;
cout << "Type: " << typeid(animal).name() << endl;
animal.makeSound();
animal.move();
// 使用dynamic_cast检查并转换为特定类型
// 检查是否是狗
if (const Dog* dog = dynamic_cast<const Dog*>(&animal)) {
cout << "Breed: " << dog->getBreed() << endl;
dog->fetch();
}
// 检查是否是猫
else if (const Cat* cat = dynamic_cast<const Cat*>(&animal)) {
cat->climbTree();
}
// 检查是否是鸟
else if (const Bird* bird = dynamic_cast<const Bird*>(&animal)) {
bird->flyHigh();
}
else {
cout << "Unknown animal type." << endl;
}
}
// 使用typeid比较类型
void compareTypes(const Animal& a1, const Animal& a2) {
cout << "\nComparing types:" << endl;
cout << a1.getName() << " is type: " << typeid(a1).name() << endl;
cout << a2.getName() << " is type: " << typeid(a2).name() << endl;
if (typeid(a1) == typeid(a2)) {
cout << "They are the same type of animal." << endl;
}
else {
cout << "They are different types of animals." << endl;
}
}
int main() {
// 创建不同类型的动物
Dog dog("Buddy", "Golden Retriever");
Cat cat("Whiskers");
Bird bird("Tweety");
// 处理各种动物
processAnimal(dog);
processAnimal(cat);
processAnimal(bird);
// 通过基类指针数组处理动物
Animal* animals[] = {&dog, &cat, &bird};
cout << "\n=== Processing animals through base pointers ===" << endl;
for (const auto& animal : animals) {
animal->makeSound();
// 使用dynamic_cast进行向下转换
if (Dog* d = dynamic_cast<Dog*>(animal)) {
d->fetch();
}
}
// 比较动物类型
compareTypes(dog, cat);
compareTypes(cat, *animals[1]); // 比较猫和通过指针访问的猫
// 错误的类型转换示例
cout << "\n=== Testing invalid cast ===" << endl;
Animal* animalPtr = &dog;
Cat* catPtr = dynamic_cast<Cat*>(animalPtr);
if (catPtr) {
cout << "Cast succeeded: " << catPtr->getName() << endl;
}
else {
cout << "Cast failed: Cannot cast Dog to Cat" << endl;
}
return 0;
}
上面的代码展示了 RTTI 的主要用法:
dynamic_cast用于安全地将基类指针或引用转换为派生类指针或引用。如果转换失败,对于指针会返回nullptr,对于引用会抛出bad_cast异常。
typeid用于获取对象的类型信息,可以:
typeid(obj).name()typeid(a) == typeid(b)使用 RTTI 时需要注意:
C++ 中虚函数的动态绑定(也称为迟绑定)是通过虚函数表(vtable)和虚表指针(vptr)实现的,这是编译器层面的实现机制。
基本原理:

下面的代码可以帮助理解虚函数表的概念(注意:这只是概念演示,实际实现可能因编译器而异):
#include <iostream>
using namespace std;
// 基类
class Base {
public:
virtual void func1() { cout << "Base::func1()" << endl; }
virtual void func2() { cout << "Base::func2()" << endl; }
void nonVirtualFunc() { cout << "Base::nonVirtualFunc()" << endl; }
};
// 派生类
class Derived : public Base {
public:
void func1() override { cout << "Derived::func1()" << endl; } // 重写func1
virtual void func3() { cout << "Derived::func3()" << endl; } // 新增虚函数
};
// 打印虚函数表(仅作演示,依赖于特定编译器实现)
void printVTable(void* obj) {
// 假设vptr是对象的第一个成员
void** vtable = *reinterpret_cast<void***>(obj);
cout << "VTable address: " << vtable << endl;
// 打印前几个虚函数(实际数量未知,这里只打印几个)
for (int i = 0; i < 3; ++i) {
cout << "VTable[" << i << "]: " << vtable[i];
// 尝试调用函数(不安全,仅作演示)
using FuncType = void(*)();
FuncType func = reinterpret_cast<FuncType>(vtable[i]);
if (func) {
cout << " -> ";
func(); // 注意:这样调用没有this指针,实际中会出错
}
cout << endl;
}
}
int main() {
Base base;
Derived derived;
cout << "=== Base object vtable ===" << endl;
printVTable(&base);
cout << "\n=== Derived object vtable ===" << endl;
printVTable(&derived);
cout << "\n=== Polymorphic behavior ===" << endl;
Base* basePtr = &derived;
basePtr->func1(); // 调用Derived::func1()
basePtr->func2(); // 调用Base::func2(),未被重写
// 下面的代码无法编译,因为基类中没有func3()
// basePtr->func3();
// 需要显式转换才能调用派生类特有函数
if (Derived* dPtr = dynamic_cast<Derived*>(basePtr)) {
dPtr->func3();
}
return 0;
}虚函数动态绑定的优点:
虚函数的开销:
本章详细介绍了 C++ 中的多态性,主要内容总结如下:
virtual的函数,允许派生类重写。通过基类指针或引用调用虚函数时,会根据对象的实际类型调用相应的函数版本,实现动态绑定。
virtual 返回类型 函数名() = 0)。包含纯虚函数的类为抽象类,不能实例化,只能作为基类使用,强制派生类实现接口。
dynamic_cast和typeid多态性是 C++ 中非常强大的特性,合理使用多态可以提高代码的可读性、可维护性和可扩展性。掌握多态性的概念和实现机制,对于编写高质量的面向对象 C++ 程序至关重要。
通过本章的学习和实例练习,应该能够理解多态性的原理,并能在实际编程中灵活运用虚函数、纯虚函数和抽象类等特性,设计出更加优雅和高效的 C++ 程序。
希望本章的内容对您有所帮助!如有任何问题或建议,欢迎在评论区留言讨论。
以上就是《C++ 程序设计》第 8 章 - 多态性的全部内容。本文提供的所有代码都经过测试,可以直接编译运行。建议读者动手实践这些示例,加深对多态性的理解和应用能力。
祝大家学习愉快,编程顺利!