// Shape.h - 动态库接口定义
#ifndef SHAPE_API_H
#define SHAPE_API_H
#ifdef _WIN32
#ifdef SHAPE_EXPORTS
#define SHAPE_API __declspec(dllexport)
#else
#define SHAPE_API __declspec(dllimport)
#endif
#else
#define SHAPE_API __attribute__((visibility("default")))
#endif
// 抽象基类(接口)
class SHAPE_API IShape {
public:
virtual ~IShape() {}
virtual void Draw() const = 0;
virtual double Area() const = 0;
virtual void Move(double dx, double dy) = 0;
};
// 工厂函数声明
extern "C" {
SHAPE_API IShape* CreateCircle(double x, double y, double radius);
SHAPE_API IShape* CreateRectangle(double x, double y, double width, double height);
SHAPE_API void DestroyShape(IShape* shape);
}
#endif // SHAPE_API_H
// ShapeExports.cpp - 动态库导出实现
#include "Shape.h"
#include "Circle.h"
#include "Rectangle.h"
// 导出工厂函数实现
extern "C" {
SHAPE_API IShape* CreateCircle(double x, double y, double radius) {
return new Circle(x, y, radius);
}
SHAPE_API IShape* CreateRectangle(double x, double y, double width, double height) {
return new Rectangle(x, y, width, height);
}
SHAPE_API void DestroyShape(IShape* shape) {
delete shape;
}
}
// Circle.h - 不导出实现类,仅内部使用
#ifndef CIRCLE_H
#define CIRCLE_H
#include "Shape.h"
class Circle : public IShape {
// ... 保持原有实现不变 ...
};
#endif // CIRCLE_H
// Rectangle.h - 不导出实现类,仅内部使用
#ifndef RECTANGLE_H
#define RECTANGLE_H
#include "Shape.h"
class Rectangle : public IShape {
// ... 保持原有实现不变 ...
};
#endif // RECTANGLE_H
导出符号控制:
__declspec(dllexport/dllimport)
__attribute__((visibility("default")))
SHAPE_API
宏统一处理C语言接口导出:
extern "C"
确保函数名不被修饰隐藏实现细节:
Circle
/Rectangle
)内存管理:
DestroyShape
函数二进制兼容性:
SHAPE_EXPORTS
宏编译命令示例:
g++ -fPIC -DSHAPE_EXPORTS -shared ShapeExports.cpp Circle.cpp Rectangle.cpp -o libshape.so
// client.cpp
#include "Shape.h"
#include
int main() {
// 使用动态库提供的工厂函数
IShape* circle = CreateCircle(10, 20, 5);
IShape* rect = CreateRectangle(30, 40, 10, 20);
circle->Draw();
std::cout << "Circle area: " << circle->Area() << std::endl;
rect->Draw();
std::cout << "Rectangle area: " << rect->Area() << std::endl;
// 使用动态库提供的销毁函数
DestroyShape(circle);
DestroyShape(rect);
return 0;
}
cl client.cpp /Ipath_to_headers /link shape.lib
g++ client.cpp -Ipath_to_headers -L. -lshape -o client
这样改造后,你的接口可以作为动态库安全地提供给其他C++项目使用,同时保持二进制兼容性和实现细节的隐藏。
虚函数机制:确实,通过虚函数表(vtable),客户端代码可以通过基类指针调用子类实现,而不需要知道具体子类信息。
导出接口类的必要性:
不导出接口类的潜在问题:
// 正确做法 - 导出接口类
class SHAPE_API IShape {
public:
virtual ~IShape() {}
virtual void Draw() const = 0;
// ...
};
// 实现类不应导出 (保持在内部)
class Circle : public IShape { /*...*/ }; // 没有 SHAPE_API
Windows平台:
Linux/macOS平台:
内存管理:
// Shape.h
#ifndef SHAPE_API_H
#define SHAPE_API_H
#ifdef _WIN32
#ifdef SHAPE_EXPORTS
#define SHAPE_API __declspec(dllexport)
#else
#define SHAPE_API __declspec(dllimport)
#endif
#else
#define SHAPE_API __attribute__((visibility("default")))
#endif
// 必须导出接口类
class SHAPE_API IShape {
public:
virtual ~IShape() {}
virtual void Draw() const = 0;
virtual double Area() const = 0;
virtual void Move(double dx, double dy) = 0;
};
// C接口工厂函数
extern "C" {
SHAPE_API IShape* CreateCircle(double x, double y, double radius);
SHAPE_API IShape* CreateRectangle(double x, double y, double width, double height);
SHAPE_API void DestroyShape(IShape* shape);
}
#endif // SHAPE_API_H
二进制兼容性:
跨编译器兼容:
明确接口边界:
如果确实不想导出整个接口类,可以采用PIMPL模式的变种:
// 替代方案 - 不导出接口类,使用opaque指针
extern "C" {
typedef struct IShape IShape; // 前向声明
SHAPE_API IShape* CreateCircle(double x, double y, double radius);
SHAPE_API void DrawShape(const IShape* shape);
SHAPE_API double GetArea(const IShape* shape);
SHAPE_API void DestroyShape(IShape* shape);
}
但这种做法:
最佳实践是导出接口类,因为:
虽然技术上在某些平台/编译器组合下可能不导出接口类也能工作,但导出接口类是更可靠、更可移植的做法。