error c2243:"类型转换" 转换存在,但无法访问

本文探讨了当派生类采用私有或受保护继承时,基类指针或引用是否能访问派生类对象的问题,并通过实验验证了系统不允许此类类型转换。

最近重新看了遍基类指针、引用的相关知识点,一直在想 ,如果派生类不是公有继承,那么用基类指针、引用指向该派生类对象时会发生什么?派生类内的成员的访问权限会不会发生什么变化?

结果实验表明,系统不支持此类类型转换。基类指针、引用不能指向继承方式为protected与private的派生类对象。

假设我们有以下类:

class A
{
public:
	int publi;
protected:
	int prote;
private:
	int pri;
};

class B : private A
{
public:
protected:
private:
};
当我们调用以下语句时:

B b;
A &a = b;

系统将会报错:error C2243: “类型转换”: 从“B *”到“A &”的转换存在,但无法访问。同理,私有继承也同样会报错。

私有派生,原来的公有成员与保护成员,在派生类中均为私有的。那么使用基类指针或引用,能不能调用私有派生类继承过来的(在基类中原来是公有成员)私有成员?显然不能呀(破坏了类的封装性)

所以,需要注意的是基类指针、引用不能指向继承方式为protected与private的派生类对象。


<think>我们正在解决用户在使用OpenCV的`getWindowProperty`函数获取窗口句柄时遇到的类型转换错误问题。用户希望将返回值转换为`HWND`(Windows平台下的窗口句柄类型)。 根据之前的讨论,我们知道在OpenCV 4.x中,`cvGetWindowHandle`已经被移除,替代方案是使用`cv::getWindowProperty`并指定属性为`cv::WND_PROP_HANDLE`。在Windows平台上,这个函数应该返回一个`HWND`类型的句柄。但是,用户遇到了类型转换错误,这通常是因为返回值类型不匹配。 ### 问题分析 1. **函数原型**:在OpenCV中,`getWindowProperty`的函数原型为: ```cpp double cv::getWindowProperty(const String& winname, int prop_id) ``` 注意,它返回的是`double`类型。但是,窗口句柄(`HWND`)实际上是一个指针(在64位系统中是64位整数)。因此,我们需要将`double`类型的返回值转换为指针类型。 2. **转换方法**:在C++中,我们不能直接将`double`转换为指针,因为这样会丢失精度(尤其是当指针值不能精确表示为`double`时)。正确的做法是使用`cv::getWindowProperty`的另一个重载版本,它返回`void*`,这样我们就可以直接将其转换为`HWND`。 ### 解决方案 实际上,OpenCV提供了两个重载的`getWindowProperty`函数: ```cpp double getWindowProperty(const String& winname, int prop_id); void* getWindowProperty(const String& winname, int prop_id, bool allow_retrieval = true); ``` 我们需要使用的是第二个重载,它直接返回`void*`,这样我们就可以安全地将其转换为`HWND`。 ### 正确代码示例 ```cpp #include <opencv2/highgui.hpp> #include <windows.h> // 包含HWND的定义 int main() { cv::namedWindow("Example", cv::WINDOW_NORMAL); // 获取窗口句柄,使用返回void*的重载 void* ptr = cv::getWindowProperty("Example", cv::WND_PROP_HANDLE, true); // 将void*转换为HWND HWND hwnd = static_cast<HWND>(ptr); // 现在可以使用hwnd进行Windows API操作 // 例如:SetWindowText(hwnd, L"New Title"); cv::waitKey(0); return 0; } ``` ### 注意事项 1. **平台兼容性**:上述代码仅适用于Windows平台。在Linux上,返回的是X11的`Window`类型(也是指针),在macOS上是`NSWindow*`。 2. **窗口存在性**:在调用`getWindowProperty`之前,确保窗口已经创建(即`namedWindow`之后)。如果窗口尚未创建,则返回的指针可能为`nullptr`。 3. **错误处理**:建议在使用`hwnd`之前检查其是否为`nullptr`,以避免访问违规。 ### 常见错误 如果使用了返回`double`的版本,并尝试强制转换,例如: ```cpp HWND hwnd = (HWND)(cv::getWindowProperty("Example", cv::WND_PROP_HANDLE)); ``` 这可能会导致运行时错误,因为`double`类型无法精确表示64位整数(指针)。因此,必须使用返回`void*`的重载版本。 ### 为什么会有两个重载? - 返回`double`的版本是为了兼容性(可能是为了与某些脚本语言绑定兼容)。 - 返回`void*`的版本是C++中获取指针类型属性的正确方式。 ### 如果编译报错找不到返回void*的重载? 请确保: 1. 包含正确的头文件:`#include <opencv2/highgui.hpp>` 2. 使用OpenCV 4.x版本(该重载在OpenCV 3.x中可能不存在,但在4.x中是存在的) ### 验证 可以通过以下方式验证: ```cpp void* ptr = cv::getWindowProperty("Example", cv::WND_PROP_HANDLE, true); if (ptr == nullptr) { std::cerr << "Failed to get window handle!" << std::endl; } else { std::cout << "Window handle: " << ptr << std::endl; } ``` ### 相关问题 1. 在OpenCV中如何设置窗口图标(使用获取的HWND)? 2. 如何检测用户是否点击了OpenCV窗口的关闭按钮? 3. 在跨平台开发中,如何根据不同的操作系统处理窗口句柄? 4. 如何修改OpenCV窗口的样式(例如,去掉边框)? 通过以上步骤,用户应该能够正确获取OpenCV窗口的句柄并避免类型转换错误。</think>### OpenCV `getWindowProperty` 返回值无法转换为 `HWND` 的解决方案 在 OpenCV 4.x 中,使用 `getWindowProperty()` 获取窗口句柄时,返回值类型转换错误通常由以下原因引起: #### 1. **错误的返回值类型处理** ```cpp // 错误用法:返回 double 类型无法直接转 HWND HWND hwnd = (HWND)cv::getWindowProperty("Window", cv::WND_PROP_HANDLE); ``` `getWindowProperty()` 默认返回 `double` 类型,而 `HWND` 是指针类型(64位系统为8字节),直接转换会导致精度丢失或类型不匹配[^1]。 #### 2. **正确解决方案(Windows 平台)** ```cpp #include <opencv2/highgui.hpp> #include <windows.h> // 获取窗口句柄的正确方式 void* ptr = cv::getWindowProperty("Window", cv::WND_PROP_HANDLE, true); HWND hwnd = static_cast<HWND>(ptr); ``` 关键点: - 使用三参数重载版本:`getWindowProperty(winname, prop_id, allow_retrieval)` - 设置 `allow_retrieval=true` 强制返回 `void*` 类型 - 通过 `static_cast` 安全转换为 `HWND`[^1][^2] #### 3. **跨平台兼容写法** ```cpp #if defined(_WIN32) HWND hwnd = static_cast<HWND>(cv::getWindowProperty("Window", cv::WND_PROP_HANDLE, true)); #elif defined(__APPLE__) NSWindow* nsWin = (NSWindow*)cv::getWindowProperty("Window", cv::WND_PROP_HANDLE, true); #else // Linux Window x11Win = (Window)cv::getWindowProperty("Window", cv::WND_PROP_HANDLE, true); #endif ``` #### 4. **验证窗口句柄有效性** ```cpp if (hwnd != nullptr && IsWindow(hwnd)) { SetWindowText(hwnd, L"New Title"); // 修改窗口标题 ShowWindow(hwnd, SW_MAXIMIZE); // 最大化窗口 } else { std::cerr << "Invalid window handle!" << std::endl; } ``` #### 5. **常见错误排查** | 错误现象 | 原因 | 解决方案 | |---------|------|---------| | 访问冲突 | 窗口未创建 | 确保先执行 `namedWindow()` | | 空指针 | 窗口名称错误 | 检查窗口名拼写和大小写 | | 类型转换失败 | 未使用三参数版本 | 添加 `, true` 参数 | | 句柄无效 | OpenCV 后端不支持 | 检查 `cv::getBuildInformation()` 中的 GUI 后端 | > **注意**:OpenCV 的 HighGUI 模块在某些后端(如 GTK)可能无法获取有效句柄。建议使用 `cv::getBuildInformation()` 确认编译时启用了 `WITH_WIN32UI` 支持[^3]。 ### 完整示例代码 ```cpp #include <opencv2/opencv.hpp> #include <windows.h> int main() { cv::Mat img(480, 640, CV_8UC3, cv::Scalar(0, 0, 0)); cv::namedWindow("Demo", cv::WINDOW_NORMAL); // 获取窗口句柄 void* ptr = cv::getWindowProperty("Demo", cv::WND_PROP_HANDLE, true); HWND hwnd = static_cast<HWND>(ptr); if (hwnd && IsWindow(hwnd)) { // 修改窗口属性 SetWindowText(hwnd, L"OpenCV Window Demo"); SetWindowLongPtr(hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME); // 解决引用[2]提到的白边问题 SetWindowPos(hwnd, NULL, 0, 0, 640, 480, SWP_FRAMECHANGED | SWP_NOZORDER); } cv::imshow("Demo", img); cv::waitKey(0); return 0; } ``` ### 相关问题 1. 如何解决 OpenCV 全屏模式下的像素白边问题?[^2] 2. 如何检测用户是否点击了 OpenCV 窗口的关闭按钮?[^3] 3. 跨平台开发中如何处理不同系统的窗口句柄类型? 4. OpenCV 窗口句柄获取失败的可能原因有哪些? 5. 如何通过窗口句柄修改 OpenCV 窗口的图标?[^3] [^1]: 使用 `getWindowProperty` 的三参数版本可获取正确类型句柄 [^2]: 通过 `SetWindowPos` 调整窗口尺寸可消除白边 [^3]: 获取句柄后可用原生 API 实现关闭检测和图标设置
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值