8.7 程序举例
本节通过两个例子展示了多态性和虚函数的实际应用。
例8.18 计算几种几何图形的面积之和
这个例子计算了五种几何图形(矩形、三角形、圆形、梯形、正方形)的面积之和。以下是程序的实现:
#include <iostream>
using namespace std;
class Shape {
public:
virtual double Area() const = 0;
};
class Triangle : public Shape {
public:
Triangle(double h, double w) : H(h), W(w) {}
double Area() const override {
return H * W * 0.5;
}
private:
double H, W;
};
class Rectangle : public Shape {
public:
Rectangle(double h, double w) : H(h), W(w) {}
double Area() const override {
return H * W;
}
private:
double H, W;
};
class Circle : public Shape {
public:
Circle(double r) : radius(r) {}
double Area() const override {
return radius * radius * 3.1415;
}
private:
double radius;
};
class Trapezoid : public Shape {
public:
Trapezoid(double top, double bottom, double high)
: T(top), B(bottom), H(high) {}
double Area() const override {
return (T + B) * H * 0.5;
}
private:
double T, B, H;
};
class Square : public Shape {
public:
Square(double side) : S(side) {}
double Area() const override {
return S * S;
}
private:
double S;
};
class Application {
public:
double Compute(Shape* s[], int n) const {
double sum = 0;
for (int i = 0; i < n; ++i)
sum += s[i]->Area();
return sum;
}
};
class MyProgram : public Application {
public:
MyProgram() {
s = new Shape*[5];
s[0] = new Triangle(3.0, 4.0);
s[1] = new Rectangle(6.0, 8.0);
s[2] = new Circle(6.5);
s[3] = new Trapezoid(10.0, 8.0, 5.0);
s[4] = new Square(6.7);
}
~MyProgram() {
for (int i = 0; i < 5; ++i)
delete s[i];
delete[] s;
}
double Run() {
return Compute(s, 5);
}
private:
Shape** s;
};
int main() {
cout << "Area's sum = " << MyProgram().Run() << endl;
return 0;
}
说明
- 抽象类 Shape:定义了一个纯虚函数
Area
,作为所有几何图形的基类。 - 五个派生类:
Triangle
、Rectangle
、Circle
、Trapezoid
和Square
,每个类都实现了Area
函数。 - Application 类:包含一个计算面积和的函数
Compute
。 - MyProgram 类:继承自
Application
,在构造函数中创建了五个几何图形对象,在析构函数中删除这些对象。
程序的输出结果为:
mathematica
复制代码
Area's sum = 276.618
这种结构使得添加新图形非常方便,只需增加一个继承自 Shape
的派生类并实现 Area
函数即可。
例8.19 宠物管理系统
该例子展示了一个宠物管理系统,假设一个人拥有20个宠物窝,一半用于养猫,另一半用于养狗。程序定义了一个动物基类 Animal
,以及 Cat
和 Dog
两个派生类,并实现了虚函数 WhoAmI
。
#include <iostream>
#include <cstring>
using namespace std;
class Animal {
public:
Animal() : name(nullptr) {}
Animal(const char* n) : name(strdup(n)) {}
virtual ~Animal() { delete[] name; }
virtual void WhoAmI() { cout << "generic animal." << endl; }
protected:
char* name;
};
class Cat : public Animal {
public:
Cat() : Animal() {}
Cat(const char* n) : Animal(n) {}
void WhoAmI() override {
cout << "I am a cat named " << name << endl;
}
};
class Dog : public Animal {
public:
Dog() : Animal() {}
Dog(const char* n) : Animal(n) {}
void WhoAmI() override {
cout << "I am a dog named " << name << endl;
}
};
class Kennel {
public:
Kennel(unsigned max);
~Kennel();
unsigned Accept(Animal* d);
Animal* Release(unsigned pen);
void ListAnimals();
private:
unsigned MaxAnimals, NumAnimals;
Animal** Residents;
};
Kennel::Kennel(unsigned max) : MaxAnimals(max), NumAnimals(0) {
Residents = new Animal*[MaxAnimals];
for (unsigned i = 0; i < MaxAnimals; ++i)
Residents[i] = nullptr;
}
Kennel::~Kennel() {
for (unsigned i = 0; i < MaxAnimals; ++i)
delete Residents[i];
delete[] Residents;
}
unsigned Kennel::Accept(Animal* d) {
if (NumAnimals == MaxAnimals)
return 0;
for (unsigned i = 0; i < MaxAnimals; ++i) {
if (Residents[i] == nullptr) {
Residents[i] = d;
++NumAnimals;
return i + 1;
}
}
return 0;
}
Animal* Kennel::Release(unsigned pen) {
if (pen > MaxAnimals || Residents[pen - 1] == nullptr)
return nullptr;
Animal* temp = Residents[pen - 1];
Residents[pen - 1] = nullptr;
--NumAnimals;
return temp;
}
void Kennel::ListAnimals() {
for (unsigned i = 0; i < MaxAnimals; ++i) {
if (Residents[i] != nullptr) {
cout << "The animal in pen " << i + 1 << " says:" << endl;
Residents[i]->WhoAmI();
}
}
}
Dog d1("Rover"), d2("Spot"), d3("Chip"), d4("Buddy"), d5("Butch");
Cat c1("Tinkerbell"), c2("Inky"), c3("Fluffy"), c4("Princess"), c5("Sylvester");
int main() {
Kennel K(20);
K.Accept(&d1);
unsigned c2pen = K.Accept(&c2);
K.Accept(&d3);
K.Accept(&c1);
unsigned d4pen = K.Accept(&d4);
K.Accept(&d5);
K.Accept(&c5);
K.Release(c2pen);
K.Accept(&c4);
K.Accept(&c3);
K.Release(d4pen);
K.Accept(&d2);
K.ListAnimals();
return 0;
}
说明
- 基类 Animal:定义了虚函数
WhoAmI
,用于输出动物的身份信息。 - 派生类 Cat 和 Dog:分别实现了
WhoAmI
函数,输出各自的身份信息。 - Kennel 类:管理动物的数组,提供接收、释放和列出动物的方法。
程序的输出结果如下:
The animal in pen 1 says: I am a dog named Rover
The animal in pen 2 says: I am a cat named Princess
The animal in pen 3 says: I am a dog named Chip
The animal in pen 4 says: I am a cat named Tinkerbell
The animal in pen 5 says: I am a dog named Spot
The animal in pen 6 says: I am a dog named Butch
The animal in pen 7 says: I am a cat named Sylvester
The animal in pen 8 says: I am a cat named Fluffy
这个例子展示了虚函数的使用,使得对不同类型的动物有统一的操作接口,方便地进行多态操作。
结论
通过以上两个例子,我们可以看到虚函数和多态性在实际编程中的重要应用。虚函数使得程序能够根据对象的实际类型调用相应的方法,从而实现了多态性。这种机制极大地提高了程序的灵活性和可扩展性,便于维护和扩展功能。希望本文对虚函数和多态性的理解有所帮助,为编写更灵活、更易维护的C++程序提供支持。