1. C++ 代码实现
绘制抽象类
class DrawAPI {
public:
virtual void drawShape(int x, int y, int radius) = 0;
virtual ~DrawAPI() = default;
};
OpenGL 绘制实现
class OpenGLDraw : public DrawAPI {
public:
void drawShape(int x, int y, int radius) override {
std::cout << "OpenGL绘制圆形在(" << x << ", " << y << ") 半径为 " << radius << std::endl;
}
};
Vulkan 绘制实现
class VulkanDraw : public DrawAPI {
public:
void drawShape(int x, int y, int radius) override {
std::cout << "Vulkan绘制圆形在(" << x << ", " << y << ") 半径为 " << radius << std::endl;
}
};
抽象图形类
class Shape {
protected:
DrawAPI* drawAPI;
public:
Shape(DrawAPI* drawAPI) : drawAPI(drawAPI) {}
virtual void draw() = 0;
virtual double calculateArea() = 0;
virtual ~Shape() { delete drawAPI; }
};
圆形类
class Circle : public Shape {
private:
int x, y, radius;
public:
Circle(int x, int y, int radius, DrawAPI* drawAPI) : Shape(drawAPI), x(x), y(y), radius(radius) {}
void draw() override {
drawAPI->drawShape(x, y, radius);
}
double calculateArea() override {
return 3.14159 * radius * radius;
}
};
矩形类
class Rectangle : public Shape {
private:
int x, y, width, height;
public:
Rectangle(int x, int y, int width, int height, DrawAPI* drawAPI) : Shape(drawAPI), x(x), y(y), width(width), height(height) {}
void draw() override {
std::cout << "绘制矩形在(" << x << ", " << y << ") 宽为 " << width << " 高为 " << height << std::endl;
drawAPI->drawShape(x, y, width); // 这里简单复用drawShape函数参数
}
double calculateArea() override {
return width * height;
}
};
测试代码
#include <iostream>
int main() {
DrawAPI* opengl = new OpenGLDraw();
DrawAPI* vulkan = new VulkanDraw();
Shape* circle1 = new Circle(10, 10, 5, opengl);
Shape* circle2 = new Circle(20, 20, 10, vulkan);
circle1->draw();
std::cout << "圆形1面积: " << circle1->calculateArea() << std::endl;
circle2->draw();
std::cout << "圆形2面积: " << circle2->calculateArea() << std::endl;
delete circle1;
delete circle2;
return 0;
}
2. 抽象类继承与派生规则的重要性
重要性
- 代码复用:通过继承抽象类
Shape
,具体图形类(如 Circle
和 Rectangle
)可以复用其定义的接口和部分属性,减少重复代码。例如,Shape
类中的 drawAPI
成员变量,具体图形类无需重复定义。
- 多态性:抽象类定义的纯虚函数(如
draw()
和 calculateArea()
),使得派生类可以根据自身特性实现这些函数,从而在运行时根据对象的实际类型调用正确的函数,实现多态行为。这为系统提供了灵活性和扩展性,比如可以轻松添加新的图形类型。
3. 可能遇到的问题及解决方案
问题
- 菱形继承问题:如果继承体系变得复杂,可能会出现菱形继承,导致数据冗余和歧义。例如,多个类继承自同一个抽象类,而这些类又共同继承自另一个类,会导致在最终派生类中存在多个基类副本。
- 接口与实现的耦合:虽然桥接模式旨在解耦图形类型和绘制方式,但如果抽象类设计不当,可能会导致接口与实现之间的耦合。例如,抽象类中定义的函数过于具体,限制了派生类的实现方式。
解决方案
- 使用虚继承解决菱形继承:在继承抽象类时,使用虚继承可以确保在最终派生类中只存在一份基类子对象,避免数据冗余和歧义。例如,
class Derived : virtual public Base
。
- 合理设计抽象类接口:抽象类应定义通用的、抽象的接口,避免包含过多具体实现细节。例如,
Shape
类中的 draw()
和 calculateArea()
函数定义为纯虚函数,具体实现留给派生类,这样可以最大程度地保持灵活性和解耦性。同时,通过组合(如 drawAPI
成员变量)来实现功能扩展,而不是过度依赖继承。