小弟现在正使用了一个从 CListView 继承的类 CXXXView,经常用的函数是 GetListCtrl 来得到视图的 CListCtrl 类对象,现在发现 CListCtrl 功能函数太少,想用一个 CListCtrlEx(包括设置单元格字体和背景色的功能) 替抽换,即用 GetListCtrl 时得到的是 CListCtrlEx 对象,追踪MFC的 CListView 发现
AFXCVIEW_INLINE CListCtrl& CListView::GetListCtrl() const
{ return *(CListCtrl*)this; }
无奈,现不知怎么实现我想要的功能,请各位XDJM帮帮忙!!!
在线等,谢谢!
AFXCVIEW_INLINE CListCtrl& CListView::GetListCtrl() const
{ return *(CListCtrl*)this; }
无奈,现不知怎么实现我想要的功能,请各位XDJM帮帮忙!!!
在线等,谢谢!
AFXCVIEW_INLINE CListCtrl& CListView::GetListCtrl() const
{ return *(CListCtrl*)this; }???
AFXCVIEW_INLINE CListCtrl& CListView::GetListCtrl() const
{ return *(CListCtrl*)this; }
在MFC的源代码中确实如此,看一下MFC的源代码就明白了。
{ return *(CListCtrlEx*)this; }
这样不就得了
也就是说,你可以安全地把CWnd指针转化为CEdit指针。在CWnd的窗口类为EDIT的情况下,你可以安全地用这个CEdit指针来访问CEdit具有的而CWnd不具有的特性。由于CEditView的窗口类也是EDIT,同时是从CWnd派生下来的,所以你也可以把CEditView指针转化成CEdit指针。MFC的CCtrlView的派生类都可以做这样的转化。 在这样做之前,你需要查看类的定义头文件以确保类型安全。CEdit, CListCtrl, CTreeCtrl,CToolBarCtrl都是这样的封装,但是CToolTipCtrl是一个例外。除了对TTM_ADDTOOL消息的处理可能不一致之外。 LRESULT CToolTipCtrl::OnAddTool(WPARAM wParam, LPARAM lParam)
{
TOOLINFO ti = *(LPTOOLINFO)lParam;
if ((ti.hinst == NULL) && (ti.lpszText != LPSTR_TEXTCALLBACK)
&& (ti.lpszText != NULL))
{
void* pv;
if (!m_mapString.Lookup(ti.lpszText, pv))
m_mapString.SetAt(ti.lpszText, NULL);
// set lpszText to point to the permanent memory associated
// with the CString
VERIFY(m_mapString.LookupKey(ti.lpszText, ti.lpszText));
}
return DefWindowProc(TTM_ADDTOOL, wParam, (LPARAM)&ti);
}
这里访问了CToolTipCtrl的数据成员,这样的话下面的代码看起来就似乎未必安全 _AFXCMN_INLINE CToolTipCtrl* CTreeCtrl::GetToolTips() const
{ ASSERT(::IsWindow(m_hWnd)); return (CToolTipCtrl*)CWnd::FromHandle((HWND)::SendMessage(m_hWnd, TVM_GETTOOLTIPS, 0, 0L)); }
不过CTreeCtrl::GetToolTips()返回的只是有效的CWnd,TVM_ADDTOOL消息也是被默认窗口过程而不是CToolTipCtrl的代码来处理, 所以上面的用法还是安全的。 顺便说一下,尽管大部分这样的封装是用SendMessage实现的,但是Redmond的家伙似乎很热衷于用DefWindowProc替代SendMessage来节省CPU的时钟周期。这样的一个副作用是MFC不会有处理这样的消息的机会,例如PretranslateMessage和Subclass都会失效了。强制转换的一个副作用是protected修饰符不再是类成员的保护伞。考虑如下情况
Class A
{
protected: int m_iProtected;
};
如果我想获得m_iProtected的public访问权,我可以写一个封装类
Class B:public A
{
public:int & GetProtected(){return m_iProtected;}
friend class C;
};
然后把A类型的指针强制转化成B类型的就可以以public方式访问声明为m_iProtected的成员了。在C类中访问B的成员也不受限制。 尽管多继承是C++的一个特性,从理想情况来说,CEditView应该从CCtrlView和CEdit派生出来,但是所有的人都知道多继承是多么的麻烦。对于MFC的CObject派生类,默认的情况是不允许的——尽管你可以通过的MFC技术文档TN016: Using C++ Multiple Inheritance with MFC中提供的方法手动添加多继承支持。实际上,这些特性应该以接口的形式提供——把GetEditCtrl转换成QueryInterface,但是性能上又会损失很多,而且Windows通用控件和MFC对它的封装总是在不断地升级,所以MFC使用了如上的”黑客”方法来提供和多继承类似的功能。 强制类型转换不适合内存表示不同的场合,所以只有你确定指定地址的内存布局和string相同的时候才可以访问。类的内存表示包含虚函数表和成员列表两部分。 通常,只有派生类和基类的类型不同而和基类的内存表示相同,所以派生类指针可以安全地转化为基类指针。一些不安全的类型转换也可能是可行的,只要访问的部分成员内存布局一致并且独立于其它成员就可以了。 一些字符串操作封装类内部维护一个引用计数来避免内存的频繁复制。如果对标准字符串的内存复制成为了程序的瓶颈,那么可以使用这样的类来提高性能关于移植方案如果你的CListCtrl扩展类没有增加成员变量或者虚函数(这似乎是一种缚手缚脚的扩展),那么你可以直接把任何窗口类类型为SysListView32的CWnd对象指针直接转化为你的CListCtrl扩展类指针使用。如果你的CListCtrl扩展类在CListCtrl的基础上增加了成员变量或者虚函数,那么推荐用基于CFormView(或者更麻烦一些,CCtrlView)的类来替代基于CListView的实现:在FormView的对话框上放一个列表控件,在FormView大小变化时移动列表控件以充满视图。如果你希望让视图类而不是视图中的控件来处理和响应消息,你需要捕捉控件收到的用户输入消息并通过发送WM_NOTIFY通知转发到视图,以及捕捉视图收到的控制消息并转发到控件。使用这种方法也可以自行封装基于CCtrlView的自定义控件视图类。如果你的CListCtrl扩展类不依赖于控件的状态——也就是说,由调用者手动初始化而不是自行处理创建消息,那么可以声明一个CListCtrl扩展类对象,之后调用CWnd::Attatch连接到CListView派生类对象来接管窗口过程。其它的通用控件扩展类也可以使用上述方法移植到CCtrlView派生类。