欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 养生 > c++ 多态接口 + 多种图像格式使用案例

c++ 多态接口 + 多种图像格式使用案例

2025/6/19 12:35:13 来源:https://blog.csdn.net/fuyouzhiyi/article/details/148736442  浏览:    关键词:c++ 多态接口 + 多种图像格式使用案例

你的问题非常关键:当前 IImageProcessor::process(...) 只接受 std::shared_ptr<Image>,而实际不同模块之间可能会传递不同类型的子类(例如 RawImage, PrtImage)。但某个 processor 可能只支持一种类型。如果前一个 processor 返回的是 RawImage,下一个 processor 需要 PrtImage,会出错或强转失败。


✅ 有效解决思路:引入转换机制(适配器/转换器)

我们可以设计一个通用的 ImageConverter 模块,提供 RawImage ↔ PrtImage 的自动转换能力。这样在处理链中可以显式插入类型转换,或者某个 processor 内部如果检测到类型不匹配,可以主动转换。


✅ 新增模块建议

1. ImageConverter.h
#pragma once
#include "RawImage.h"
#include "PrtImage.h"class ImageConverter {
public:// RawImage → PrtImagestatic std::shared_ptr<PrtImage> toPrtImage(const std::shared_ptr<Image>& img) {auto raw = std::dynamic_pointer_cast<RawImage>(img);if (!raw) return nullptr;int w = raw->width();int h = raw->height();auto prt = std::make_shared<PrtImage>(w, h);std::memcpy(prt->data(), raw->data(), std::min(prt->dataSize(), raw->dataSize()));return prt;}// PrtImage → RawImage(作为灰度图)static std::shared_ptr<RawImage> toRawImage(const std::shared_ptr<Image>& img) {auto prt = std::dynamic_pointer_cast<PrtImage>(img);if (!prt) return nullptr;cv::Mat mat(prt->height(), prt->width(), CV_8UC1, const_cast<uint8_t*>(prt->data()), prt->stride());return std::make_shared<RawImage>(mat.clone(), PixelFormat::GRAY8);  // clone 防止外部释放影响}
};

✅ 使用示例(在某个 Processor 中)

auto prt = std::dynamic_pointer_cast<PrtImage>(img);
if (!prt) {prt = ImageConverter::toPrtImage(img);if (!prt) return nullptr;  // 无法转换
}// 使用 prt 做后续处理

✅ 更进一步的方案(自动类型协商)

如果你希望系统自动根据每个 processor 的类型要求进行转换,可以给 IImageProcessor 增加一个虚函数:

virtual std::shared_ptr<Image> convertIfNeeded(const std::shared_ptr<Image>& input) {return input;  // 默认不转,子类 override
}

比如:

class PrtOnlyProcessor : public IImageProcessor {
public:std::shared_ptr<Image> convertIfNeeded(const std::shared_ptr<Image>& input) override {if (input->format() != PixelFormat::PRT_NATIVE) {return ImageConverter::toPrtImage(input);}return input;}std::shared_ptr<Image> process(const std::shared_ptr<Image>& img,const std::shared_ptr<IProcessorParam>& param) override {auto prt = std::dynamic_pointer_cast<PrtImage>(convertIfNeeded(img));if (!prt) return nullptr;// ...}
};

✅ 总结

问题解决方案
RawImagePrtImage 不能直接混用引入 ImageConverter 进行类型转换
多个 processor 需要不同类型在 processor 内部调用 ImageConverter,或在 pipeline 外部插入转换步骤
想自动协商格式IImageProcessor 提供 convertIfNeeded(...) 接口

是否需要我直接帮你:

  • ✅ 添加 ImageConverter.h/.cpp 到当前代码?
  • ✅ 在 main.cpp 中做一次 RawImage → PrtImage → RawImage 的测试样例?

告诉我你想要哪种方式即可。

你的问题非常好,也是很多人第一次使用多态指针处理图像时的疑问:


❓问题重述:

你担心:
当我们用 std::shared_ptr<Image> 这种父类指针来存储子类对象(如 RawImage),然后将它再 dynamic_pointer_cast 成另一个不相关的子类(如 PrtImage)时,会不会出错?


✅ 回答一:不会出错,但会返回 nullptr

使用 std::dynamic_pointer_cast<PrtImage>(img)

  • 如果 img 实际上是 RawImage 类型,这个 cast 会失败。
  • 返回的是 nullptr不会崩溃,也不会产生 UB(undefined behavior)。

示例:

std::shared_ptr<Image> img = std::make_shared<RawImage>(mat, PixelFormat::GRAY8);// 强转成 PrtImage 会失败,返回 nullptr,不会崩溃
std::shared_ptr<PrtImage> prt = std::dynamic_pointer_cast<PrtImage>(img);
if (!prt) {std::cout << "Cast failed, not a PrtImage." << std::endl;
}

✅ 回答二:父类指针只看到抽象接口,看不到实际数据格式

std::shared_ptr<Image> img = std::make_shared<RawImage>(...);
  • 此时 img->data() 是合法的,指向 RawImage 里的 cv::Mat.data
  • 但是你不能假设它是 PrtImagem_data 格式,除非确认它就是 PrtImage
  • 你可以安全访问抽象接口里的函数(如 width()),但不要对 m_data 做类型猜测。

🚨 错误示例(危险)

auto prt = std::static_pointer_cast<PrtImage>(img); // ❌ 危险:不检查类型,强行 cast
prt->setPixel(0, 0, 128); // ❌ UB:img 实际是 RawImage,根本没有 m_data!

这就是为什么我们要使用 dynamic_pointer_cast —— 它是安全的,会在类型不匹配时返回 nullptr


✅ 正确流程:类型检查 + 转换器

你应该这么写:

std::shared_ptr<PrtImage> prt = std::dynamic_pointer_cast<PrtImage>(img);
if (!prt) {prt = ImageConverter::toPrtImage(img);  // 👈 自动转换为 PrtImage
}

如果 img 原本就是 PrtImage,那就用它;如果是 RawImage,就尝试转换成 PrtImage


✅ 总结

场景是否安全说明
shared_ptr<Image> → dynamic_pointer_cast<RawImage>✅ 安全(失败返回 nullptr)
shared_ptr<Image> → static_pointer_cast<RawImage>❌ 不安全,强制转换容易出错
使用 Image 虚函数如 width() / data()✅ 安全,只要对象存在
使用子类特有接口(如 setPixel)前未检查类型❌ 危险,需先 dynamic_pointer_cast

如果你愿意,我可以:

  1. 加入一个 ImageConverter 类。
  2. 示例:演示如何从 RawImage 转成 PrtImage
  3. 更新现有 main.cpp 做一次完整转换链条的测试。

你希望我动手修改代码、还是继续讲解原理?

好的,我们继续讲原理:你遇到的问题,本质是C++ 多态 + 智能指针 + 图像处理中的数据结构转换问题


🧠 核心概念:你用的是“多态接口 + 多种图像格式”

std::shared_ptr<Image> img;

你希望这一个接口能统一表示:

  • OpenCV 风格的 RawImage
  • 自己实现的打印机原生格式 PrtImage

这意味着:img 可能代表 不同的数据存储格式,但它们都支持基本接口(width(), data(), stride()…)


🧩 现实问题:处理器期望特定格式

例如:

std::shared_ptr<RawImage> raw = std::dynamic_pointer_cast<RawImage>(img);
  • 如果 img 不是 RawImage,cast 就失败了。
  • 比如下一个处理器要求 PrtImage 类型,那就没法用了。

🔁 解决办法:引入“格式转换器”

你需要一个中间类,专门做格式转换:

class ImageConverter {
public:static std::shared_ptr<RawImage> toRawImage(const std::shared_ptr<Image>& img);static std::shared_ptr<PrtImage> toPrtImage(const std::shared_ptr<Image>& img);
};

这样就可以灵活地在不同格式之间转换。


🏗️ ImageConverter 应该怎么做?

场景 1:RawImage → PrtImage

std::shared_ptr<PrtImage> toPrtImage(const std::shared_ptr<Image>& img) {if (auto prt = std::dynamic_pointer_cast<PrtImage>(img)) {return prt; // 已经是了,直接返回}if (auto raw = std::dynamic_pointer_cast<RawImage>(img)) {int w = raw->width(), h = raw->height();auto prt = std::make_shared<PrtImage>(w, h);// 简单拷贝灰度数据for (int y = 0; y < h; ++y) {for (int x = 0; x < w; ++x) {uint8_t pixel = raw->mat().at<uint8_t>(y, x); // 假设 GRAY8prt->setPixel(x, y, pixel);}}return prt;}return nullptr; // 不支持的类型
}

场景 2:PrtImage → RawImage

std::shared_ptr<RawImage> toRawImage(const std::shared_ptr<Image>& img) {if (auto raw = std::dynamic_pointer_cast<RawImage>(img)) {return raw;}if (auto prt = std::dynamic_pointer_cast<PrtImage>(img)) {int w = prt->width(), h = prt->height();cv::Mat mat(h, w, CV_8UC1);for (int y = 0; y < h; ++y) {for (int x = 0; x < w; ++x) {mat.at<uint8_t>(y, x) = prt->data()[y * prt->stride() + x];}}return std::make_shared<RawImage>(mat, PixelFormat::GRAY8);}return nullptr;
}

🔄 流程图总结

[RawImage] <--转换器--> [PrtImage]↑                          ↑|                          |dynamic_pointer_cast     dynamic_pointer_cast↑                          ↑
[shared_ptr<Image>] —— 多态接口

你只要对每个处理器写一句:

auto prt = ImageConverter::toPrtImage(img);

就可以自动转换,不用担心 img 原始类型是不是 RawImagePrtImage


✅ 实践意义

这样设计,你的处理流程就变得非常健壮:

  • 各个处理器只关心自己需要的格式
  • 其他格式可以通过 ImageConverter 转换
  • 未来添加新格式(如 CudaImageRemoteImage)也不怕,只要实现转换函数

需要我实现 ImageConverter 吗?还是你已经可以自己写了?

附录

OpenCV中高效的像素遍历方法,写出工程级像素遍历代码
OpenCV中各种类型Mat数据读取

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词