C++面向对象之多态示例——代码抽象和封装

通过将派生类指针转换为基类指针可以实现很多功能,例如多态,接口抽象与实现分离,回调机制设计,工厂模式等。

多态性实现

多态是指同一操作(如方法调用)作用于不同的对象时,可以产生不同的行为,具体行为由对象自身的类型决定。

函数参数通用化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Animal {
public:
virtual void speak() const = 0;
virtual ~Animal() = default;
};

class Dog : public Animal {
public:
void speak() const override { cout << "Woof!" << endl; }
};

class Cat : public Animal {
public:
void speak() const override { cout << "Meow!" << endl; }
};

// 单一函数处理所有动物类型
void makeAnimalSpeak(Animal* animal) {
animal->speak(); // 多态调用
}

// 使用
Dog dog;
Cat cat;
makeAnimalSpeak(&dog); // 输出 "Woof!"
makeAnimalSpeak(&cat); // 输出 "Meow!"

容器存储异构对象

统一容器管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
vector<Animal*> zoo;
zoo.push_back(new Dog());
zoo.push_back(new Cat());
zoo.push_back(new Dog());

// 统一处理所有动物
for (Animal* animal : zoo) {
animal->speak(); // 各自调用正确的实现
}

// 清理资源
for (Animal* animal : zoo) {
delete animal;
}

接口抽象与实现分离

设计模式应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class Shape {
public:
virtual double area() const = 0;
virtual void draw() const = 0;
virtual ~Shape() = default;
};

class Circle : public Shape {
double radius;
public:
Circle(double r) : radius(r) {}
double area() const override { return 3.14 * radius * radius; }
void draw() const override { cout << "Drawing circle" << endl; }
};

class Rectangle : public Shape {
double width, height;
public:
Rectangle(double w, double h) : width(w), height(h) {}
double area() const override { return width * height; }
void draw() const override { cout << "Drawing rectangle" << endl; }
};

// 图形编辑器可以统一处理所有形状
class GraphicsEditor {
vector<Shape*> shapes;
public:
void addShape(Shape* shape) {
shapes.push_back(shape);
}

double totalArea() const {
double total = 0;
for (Shape* shape : shapes) {
total += shape->area(); // 多态调用
}
return total;
}
};

// 使用
Application myText;
Application mySpred;

myText.createDocument("text");
mySpred.createDocument("spreadsheet");

myText.workWithDocument();
mySpred.workWithDocument();

回调机制与事件处理

事件系统

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class EventListener {
public:
virtual void onEvent(const string& event) = 0;
virtual ~EventListener() = default;
};

class Button {
EventListener* listener;
public:
void setListener(EventListener* l) { listener = l; }
void click() {
if (listener) {
listener->onEvent("button_clicked");
}
}
};

class MyApp : public EventListener {
public:
void onEvent(const string& event) override {
cout << "Handling event: " << event << endl;
}
};

// 使用
MyApp app;
Button button;
button.setListener(&app); // 派生类指针转为基类指针
button.click(); // 输出 "Handling event: button_clicked"

工厂模式与对象创建

灵活的对象创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class Document {
public:
virtual void open() = 0;
virtual void save() = 0;
virtual ~Document() = default;
};

class TextDocument : public Document {
public:
void open() override { cout << "Opening text document" << endl; }
void save() override { cout << "Saving text document" << endl; }
};

class SpreadsheetDocument : public Document {
public:
void open() override { cout << "Opening spreadsheet" << endl; }
void save() override { cout << "Saving spreadsheet" << endl; }
};

class Application {
Document* currentDoc;
public:
void createDocument(const string& type) {
if (type == "text") {
currentDoc = new TextDocument(); // 派生类→基类
} else if (type == "spreadsheet") {
currentDoc = new SpreadsheetDocument(); // 派生类→基类
}
}

void workWithDocument() {
if (currentDoc) {
currentDoc->open();
currentDoc->save(); // 多态行为
}
}
};

// 使用
// 使用
Application myText;
Application mySpred;

myText.createDocument("text");
mySpred.createDocument("spreadsheet");

myText.workWithDocument();
mySpred.workWithDocument();

这样做的好处?

指的是将派生类指针转换为基类指针

抽象和封装

  • 客户端代码只需要了解基类接口
  • 隐藏具体实现细节

扩展性

  • 添加新的派生类不需要修改现有代码
  • 符合开闭原则
1
2
3
4
5
6
7
8
9
// 添加新的动物类型不需要修改现有代码
class Bird : public Animal {
public:
void speak() const override { std::cout << "Chirp!\n"; }
};

// 现有代码自动支持新类型
Bird bird;
makeAnimalSpeak(&bird); // 输出: Chirp!

维护性

  • 逻辑集中在基类接口
  • 降低代码耦合度

设计灵活性

支持各种设计模式:

  • 策略模式
  • 观察者模式
  • 命令模式
  • 等等…

类型安全

  • 编译时检查接口一致性
  • 比 C 风格强制转换更安全

设计清晰

  • 明确表达"是一个"的关系
  • 符合面向对象设计原则

总结:向上转换(派生类→基类)是面向对象编程的基石,它实现了多态性、代码复用和灵活的软件架构,是编写可维护、可扩展代码的关键技术。