C++模板与多态结合:含BufferCalculation模板的Camera类GUI实现问题
解决带模板BufferCalculation的Camera多态适配问题
嘿,这个问题我之前也碰到过类似的情况——C++里不同模板实例化的类是完全独立的类型,直接用Camera*肯定不行,得想办法把模板的差异给封装起来。给你几个实用的方案,你可以根据自己的现有代码结构来选:
方案一:给Camera和BufferCalculation加非模板抽象基类
这是最符合多态设计思路的做法,先把所有Camera的公共行为抽成纯虚基类,同时把BufferCalculation里需要在GUI里调用的操作也抽象成非模板基类:
// 先抽象BufferCalculation的公共接口 class IBufferCalculation { public: virtual ~IBufferCalculation() = default; // 把GUI要用到的操作都声明成纯虚函数 virtual void process() = 0; virtual size_t getBufferSize() const = 0; // 其他你需要的公共方法... }; template <typename T> class BufferCalculation : public IBufferCalculation { public: void process() override { // 你原来的模板实现代码 } size_t getBufferSize() const override { return sizeof(T) * bufferCount; // 假设bufferCount是类里的成员变量 } // 原来的模板特化代码... }; // 再抽象Camera的公共接口 class ICamera { public: virtual ~ICamera() = default; virtual IBufferCalculation* getBufferCalculation() = 0; virtual void startCapture() = 0; virtual void stopCapture() = 0; // 其他Camera的公共操作... }; template <typename T> class Camera : public ICamera { private: BufferCalculation<T> bufferCalculation; public: IBufferCalculation* getBufferCalculation() override { return &bufferCalculation; } void startCapture() override { // 原来的模板实现 } void stopCapture() override { // 原来的模板实现 } // 原来的模板特化代码... }; // 现在CameraGui就能用非模板的基类指针了 class CameraGui { private: ICamera* camera; public: void setCamera(ICamera* cam) { camera = cam; } void processBuffer() { if (camera) { camera->getBufferCalculation()->process(); size_t size = camera->getBufferCalculation()->getBufferSize(); // 用这些接口做GUI相关的处理 } } }; // 原来的Camera子类完全不用改 class Camera1 : public Camera<unsigned char> {}; class Camera2 : public Camera<unsigned short> {};
这个方案的好处是GUI只依赖抽象接口,完全不用关心具体的模板类型。需要注意的是,所有要在GUI里调用的方法,都得提前在非模板基类里声明好。
方案二:用类型擦封装Camera(不修改原有结构)
如果你不想动原来的Camera和BufferCalculation的继承关系,可以用类型擦除技术,把带模板参数的Camera包成一个非模板的wrapper类:
class CameraWrapper { public: template <typename CameraType> CameraWrapper(CameraType* cam) : impl(std::make_unique<Model<CameraType>>(cam)) {} // 把需要的公共接口都声明在这里,内部转发给实际的Camera对象 void startCapture() { impl->startCapture(); } void stopCapture() { impl->stopCapture(); } void processBuffer() { impl->processBuffer(); } private: // 抽象基类,定义公共接口 class Concept { public: virtual ~Concept() = default; virtual void startCapture() = 0; virtual void stopCapture() = 0; virtual void processBuffer() = 0; }; // 模板实现类,持有具体的Camera对象 template <typename CameraType> class Model : public Concept { private: CameraType* camera; public: Model(CameraType* cam) : camera(cam) {} void startCapture() override { camera->startCapture(); } void stopCapture() override { camera->stopCapture(); } void processBuffer() override { camera->bufferCalculation.process(); } }; std::unique_ptr<Concept> impl; }; // 现在CameraGui直接用CameraWrapper就行 class CameraGui { private: CameraWrapper camera; public: CameraGui(ICamera* cam) : camera(cam) {} void doWork() { camera.startCapture(); camera.processBuffer(); camera.stopCapture(); } };
这个方案的优势是完全不用改原来的模板类结构,通过wrapper把模板类型给藏起来了。缺点是每次要加新的接口,都得在CameraWrapper、Concept和Model里同步添加。
方案三:用访问者模式处理不同Buffer类型
如果你的GUI需要针对不同的Buffer类型做不一样的处理,那访问者模式会很合适,能避免那种麻烦的类型转换:
// 先定义访问者基类,每个Buffer类型对应一个visit方法 class BufferVisitor { public: virtual ~BufferVisitor() = default; virtual void visit(BufferCalculation<unsigned char>&) = 0; virtual void visit(BufferCalculation<unsigned short>&) = 0; // 以后加新的Buffer类型,就在这里加对应的visit方法 }; // 修改BufferCalculation模板类,添加accept方法来接受访问者 template <typename T> class BufferCalculation { public: void accept(BufferVisitor& visitor) { visitor.visit(*this); } // 原来的代码... }; // 抽象Camera基类,添加接受访问者的方法 class ICamera { public: virtual ~ICamera() = default; virtual void acceptBufferVisitor(BufferVisitor& visitor) = 0; // 其他公共接口... }; template <typename T> class Camera : public ICamera { private: BufferCalculation<T> bufferCalculation; public: void acceptBufferVisitor(BufferVisitor& visitor) override { bufferCalculation.accept(visitor); } // 原来的代码... }; // 在CameraGui里定义具体的访问者,处理不同类型的Buffer class GuiBufferHandler : public BufferVisitor { public: void visit(BufferCalculation<unsigned char>& buf) override { // 针对unsigned char类型的Buffer做GUI处理 std::cout << "处理unsigned char类型的缓冲区" << std::endl; } void visit(BufferCalculation<unsigned short>& buf) override { // 针对unsigned short类型的Buffer做GUI处理 std::cout << "处理unsigned short类型的缓冲区" << std::endl; } }; class CameraGui { private: ICamera* camera; GuiBufferHandler handler; public: void processBuffer() { if (camera) { camera->acceptBufferVisitor(handler); } } };
这个方案适合需要对不同Buffer类型做差异化GUI逻辑的场景,把类型相关的逻辑都集中在访问者类里,符合开闭原则,以后加新类型也方便。
内容的提问来源于stack exchange,提问作者XaBerr
相关产品推荐
相关产品推荐

