C++中如何编写继承应用IShape接口的Triangle类DLL插件(显式链接)
实现方案
一、调整主程序IShape接口的可访问性
- 必须将主程序中的
IShape接口声明为可导出/导入的共享接口,这样DLL才能继承它。在主程序的头文件中添加宏控制:#ifdef SHAPE_EXPORTS #define SHAPE_API __declspec(dllexport) #else #define SHAPE_API __declspec(dllimport) #endif class SHAPE_API IShape { public: virtual double GetArea() const = 0; virtual double GetPerimeter() const = 0; virtual ~IShape() = default; // 主程序原有创建已知形状的工厂方法保留 static IShape* Create(const std::string& shapeData); }; - 主程序编译时定义
SHAPE_EXPORTS宏,确保接口符号被导出到run.exe中。
二、编写Triangle.dll的核心代码
- 创建DLL项目,引入主程序的
IShape.h头文件(编译时不定义SHAPE_EXPORTS,自动启用__declspec(dllimport)导入接口)。 - 实现继承
IShape的Triangle类,并导出供主程序调用的C风格函数(避免C++名称 mangling):#include "IShape.h" #include <cmath> #include <string> #include <sstream> class Triangle : public IShape { private: double sideA, sideB, sideC; public: Triangle(double a, double b, double c) : sideA(a), sideB(b), sideC(c) {} double GetArea() const override { double semiPerim = (sideA + sideB + sideC) / 2; return sqrt(semiPerim * (semiPerim - sideA) * (semiPerim - sideB) * (semiPerim - sideC)); } double GetPerimeter() const override { return sideA + sideB + sideC; } }; // 导出:判断是否为三角形类型 extern "C" __declspec(dllexport) bool IsTriangle(const std::string& shapeType) { return shapeType == "triangle"; } // 导出:创建Triangle实例 extern "C" __declspec(dllexport) IShape* CreateTriangle(const std::string& shapeData) { // 解析格式如"triangle:3,4,5"的数据 size_t colonPos = shapeData.find(':'); if (colonPos == std::string::npos) return nullptr; std::string sidesStr = shapeData.substr(colonPos + 1); std::stringstream ss(sidesStr); std::string segment; double sides[3]; int idx = 0; while (std::getline(ss, segment, ',') && idx < 3) { sides[idx++] = std::stod(segment); } if (idx != 3) return nullptr; return new Triangle(sides[0], sides[1], sides[2]); }
三、主程序添加显式加载DLL的逻辑(仅少量修改)
- 在主程序中添加动态加载DLL、调用导出函数的代码,无需修改原有形状处理核心逻辑:
#include <windows.h> #include <vector> #include <string> // 定义DLL导出函数的指针类型 typedef bool (*IsShapeTypeFunc)(const std::string&); typedef IShape* (*CreateShapeFunc)(const std::string&); int main() { // 原有读取文件、处理已知形状的代码保留 std::vector<std::string> shapeDllPaths = {"Triangle.dll"}; // 可扩展为扫描目录下所有形状DLL std::vector<std::pair<IsShapeTypeFunc, CreateShapeFunc>> extShapeHandlers; // 加载DLL并注册处理函数 for (const auto& dllPath : shapeDllPaths) { HMODULE hDll = LoadLibraryA(dllPath.c_str()); if (!hDll) continue; // DLL不存在则跳过,对应版本1无Triangle支持的情况 IsShapeTypeFunc isTriangle = (IsShapeTypeFunc)GetProcAddress(hDll, "IsTriangle"); CreateShapeFunc createTriangle = (CreateShapeFunc)GetProcAddress(hDll, "CreateTriangle"); if (isTriangle && createTriangle) { extShapeHandlers.emplace_back(isTriangle, createTriangle); } } // 处理单个形状数据(示例,实际从文件批量读取) std::string shapeData = "triangle:3,4,5"; std::string shapeType = shapeData.substr(0, shapeData.find(':')); IShape* shape = nullptr; // 先尝试主程序内置的形状 shape = IShape::Create(shapeData); if (!shape) { // 尝试扩展DLL中的形状 for (const auto& handler : extShapeHandlers) { if (handler.first(shapeType)) { shape = handler.second(shapeData); break; } } } if (shape) { printf("Area: %.2f\n", shape->GetArea()); printf("Perimeter: %.2f\n", shape->GetPerimeter()); delete shape; } else { printf("Unsupported shape: %s\n", shapeType.c_str()); } // 程序退出时卸载DLL(可按需处理) // ... return 0; }
四、效果验证
- 版本1:仅运行
run.exe,因未找到Triangle.dll,加载逻辑跳过三角形处理,无法识别该形状。 - 版本2:将
Triangle.dll放在run.exe同目录下,主程序成功加载DLL,调用导出函数创建Triangle实例,正常计算并输出面积、周长。
内容的提问来源于stack exchange,提问作者Queensalats
相关产品推荐
相关产品推荐

