_AFXCVIEW_INLINE CListCtrl& CListView::GetListCtrl() const
{ return *(CListCtrl*)this; }
  从上面代码来看,CListView的指针是可以强制转换成CListCtrl指针的
  但是看过MFC中代码后发现,CListView派生自CWnd->CView->CCtrlView
  而CListCtrl直接派生自CWnd,CWnd中没有GetListCtrl这样的函数,而且CListView的实现中也没有重载CListCtrl强制转换操作符
  现在郁闷中.....求解!

解决方案 »

  1.   

    我觉得可能是这样的.
    BOOL CListCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd,
    UINT nID)
    {
    // initialize common controls
    VERIFY(AfxDeferRegisterClass(AFX_WNDCOMMCTL_LISTVIEW_REG)); CWnd* pWnd = this;
    return pWnd->Create(WC_LISTVIEW, NULL, dwStyle, rect, pParentWnd, nID);
    }
    这是CListCtrl的创建方法啊.CListCtrl也是从CWnd派生来的啊.//而最重要的就是WC_LISTVIEW 这个参数
      

  2.   

    CListCtrl和CListView的创建可能就是一样的.pWnd->Create(WC_LISTVIEW, NULL, dwStyle, rect, pParentWnd, nID);
      

  3.   

    BOOL CCtrlView::PreCreateWindow(CREATESTRUCT& cs)
    {
    ASSERT(cs.lpszClass == NULL);
    cs.lpszClass = m_strClass; // initialize common controls
    VERIFY(AfxDeferRegisterClass(AFX_WNDCOMMCTLS_REG));
    AfxDeferRegisterClass(AFX_WNDCOMMCTLSNEW_REG); // map default CView style to default style
    // WS_BORDER is insignificant
    if ((cs.style | WS_BORDER) == AFX_WS_DEFAULT_VIEW)
    cs.style = m_dwDefaultStyle & (cs.style | ~WS_BORDER); return CView::PreCreateWindow(cs);
    }
      

  4.   

    实际上CCtrlView直接以WC_LISTVIEW(对于CTreeViewCtrl就是WC_TREE)创建的,所以可以这样认为CListView实际上也是CListCtrl的派生类,所以那样转换就没有任何问题。
      

  5.   

    这是MFC为了避免多继续而采用的变通方式。
      

  6.   

    _AFXCVIEW_INLINE CListView::CListView() : CCtrlView(WC_LISTVIEW,AFX_WS_DEFAULT_VIEW)
    { }CCtrlView::CCtrlView(LPCTSTR lpszClass, DWORD dwStyle)
    {
    m_strClass = lpszClass;
    m_dwDefaultStyle = dwStyle;
    }BOOL CCtrlView::PreCreateWindow(CREATESTRUCT& cs)
    {
    ASSERT(cs.lpszClass == NULL);
    cs.lpszClass = m_strClass;
    ...其实 CListView 直接就是 CListCtrl 同一个类型的 WindowClass 的
    再直接的说 CListView 就是 CListCtrl,只是封装不同WC_LISTVIEW的定义,搜索可以看到#ifndef NOLISTVIEW#ifdef _WIN32#define WC_LISTVIEWA            "SysListView32"
    #define WC_LISTVIEWW            L"SysListView32"#ifdef UNICODE
    #define WC_LISTVIEW             WC_LISTVIEWW
    #else
    #define WC_LISTVIEW             WC_LISTVIEWA
    #endif#else
    #define WC_LISTVIEW             "SysListView"
    #endif
      

  7.   

    to happyparrot:
      我提出不存在CWnd::GetListCtrl是指不是通过虚函数实现,而某些时候类型转换的操作符也可以被重载,但正如你所说,要求内存空间中的排列吻合,但在CListView和CListCtrl代码中我没有看到这样的处理过程to etre:
      正如happyparrot所说,内存空间中的内容太大不同了to DentistryDoctor:
      获取CListCtrl的引用表明可以调用CListCtrl类的成员函数,但是在CListView仅仅和CListCtrl在上面的代码中仅仅是创建了一个类名相同的"SysListView"窗口,在指针强制转换后,CListView实现的内存空间中和CListCtrl肯定是不相同的,调用CListCtrl的成员函数岂不是会出错了?
      

  8.   

    class AFX_NOVTABLE CCtrlView : public CView可能与CCtrlView没有虚函数表有关吧,因为一般的成函数并不占其实例的内存空间,并且CListView汉有任务成员变量,所以这样应该是安全的。
      

  9.   

    先说下,CListCtrl的类中只继承了两个虚函数,如下
    virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
    virtual BOOL OnChildNotify(UINT, WPARAM, LPARAM, LRESULT*);
    而这两个都是由FrameWork来调用的,一般程序中不需要直接调用这两个函数因为CListView的m_hWnd其实就是"ListCtrl window",所以当强行转换成CListCtrl后,
    m_hWnd是正确的,但也仅需要该成员变量正确而已,因为看看CListCtrl的所有非虚成员函数,
    基本上都是通过m_hWnd对listctrl window消息的封装,而非虚成员函数在exe文件中其实等同于
    全局函数或者静态函数,只是一段代码,当调用时需传入this指针而已因此虽然CListView和CListCtrl对象的内存内容不一样,但是因为m_hWnd的内存地址是一样的(都是继承于CWnd),所以正确的使用转换后的CListCtrl指针
      

  10.   

    其实,CButton, CListCtrl, CEdit,CTreeCtrl都是假的,所有函数都是通过SendMessage实现的。
    注意,这些class中都没有成员变量。所以,MFC对窗口的包装都是假的。
      

  11.   

    众所周知,C++的多继承是个极其讨厌的东西,稍有不慎就会带来灾难
    尤其是钻石型多继承:
            A
          ↑ ↑
          B   C
          ↑ ↑
            D
    (这个图有点难看,不好意思)
    查看MFC源码,多继承的类非常少(嗯,M$那帮程序员看来也害怕多继承),
    但是却有很多类间的关系带有明显的多继承特征:
    1)CEdit继承自CWnd
    2)CEditView继承自CCtrlView,CCtrlView继承自CWnd
    实际使用中显然可以发现CEditView有很多CEdit的行为,难道CEditView重复
    了CEdit的代码?其实不然
    下面这篇文章转自微软的网站,可以发现其中一个很聪明的技巧,借此技巧也
    可以告诉我们如何实现自己的CtrlView
      

  12.   



    I made a custom control derived from CWnd, and now I want to use it as a 
    view. My first solution was to embed the control into the view and handle 
    OnSize in the view to position the control over the client area. The 
    problem is that mouse messages go to the control and cannot be overridden 
    in the view. The keystroke messages go to the view and must be manually 
    forwarded to the control.
    I read about CCtrlView as a base class for common controls. I've even 
    managed to write the view around it (I believe that you wrote about this in 
    an issue of MSJ), but I could not get it to work with my CWnd-based 
    control. Can this be done, and how?Mateo AndersonA 
    CCtrlView is a trick that MFC uses to convert control classes to view 
    classes. For example, from CTreeCtrl to CTreeView and from CListCtrl to 
    CListView. The comment in the documentation for CCtrlView says, "CCtrlView 
    allows almost any control to be a view." Unfortunately, the "almost" is a 
    bit of an exaggeration, unless by "any control" the author was thinking 
    about any of the built-in Windows? controls like CEdit, CTreeCtrl, and so 
    on. CCtrlView uses a trick that works only in special circumstances.
    To understand how CCtrlView works, let's take a look at CTreeView, which is 
    derived from CCtrlView. There are three important functions to consider: 
    the constructor, PreCreateWindow, and GetTreeCtrl.
    The constructor tells CCtrlView which kind of Windows control to create.CTreeView::CTreeView() : 
      CCtrlView(WC_TREEVIEW, dwStyle)
    {
    }In this case, WC_TREEVIEW (#defined in commctrl.h) is the name of the 
    (Windows) tree control class: namely, SysTreeView32. CCtrlView stores this 
    name in a data member for later use.CCtrlView::CCtrlView(LPCTSTR lpszClass, 
      DWORD dwStyle)
    {
      m_strClass = lpszClass;
      m_dwDefaultStyle = dwStyle;
    }The next function that comes into play is PreCreateWindow, which CTreeCtrl 
    inherits from CCtrlView. CCtrlView::PreCreateWindow uses m_strClass to set 
    the class name in the CREATESTRUCT just before the window is created.// CCtrlView uses stored class name
    BOOL CCtrlView::PreCreateWindow(CREATESTRUCT& cs)
    {
      cs.lpszClass = m_strClass;
      ???
      return CView::PreCreateWindow(cs);
    }Now the window created is of the desired class—in this case, 
    SysTreeView32. So far, so good. But if CTreeCtrl is derived from CCtrlView, 
    which is derived from CView, how can it also be derived from CTreeCtrl, the 
    MFC class that wraps the tree control? CTreeView and CTreeCtrl are 
    completely independent, with different inheritance chains. CTreeCtrl is 
    derived from CWnd directly, whereas CTreeView is derived from 
    CCtrlView/CView! This is where the trick comes in.
    To manipulate the tree view as a tree control, CTreeView provides a special 
    function, GetTreeCtrl, to get the tree control.CTreeCtrl& CTreeView::GetTreeCtrl() const

      return *(CTreeCtrl*)this; 
    }GetTreeCtrl simply casts the CTreeView to a CTreeCtrl. But wait a minute—how
     on earth can this work? The two classes are entirely different, with 
    different data members and virtual function tables—you can't just cast one 
    class to another and expect it to work!
    The answer is that CTreeCtrl has no virtual functions and no member data. 
    You could call it a pure wrapper class. CTreeCtrl doesn't add anything 
    (data or virtual functions) to its base class, CWnd; all it adds is a bunch 
    of wrapper functions, concrete functions that send messages to the 
    underlying HWND. For example:HTREEITEM CTreeCtrl::InsertItem(...)

      return (HTREEITEM)::SendMessage(m_hWnd, 
        TVM_INSERTITEM, ...);
    }The only data member that InsertItem accesses is m_hWnd, which all 
    CWnd-derived classes have. InsertItem and all the other wrapper functions 
    simply pass their arguments to the underlying HWND, converting C++-style 
    member functions to Windows-style SendMessage calls. The object itself 
    ("this" pointer) could be an instance of any CWnd-derived class, as long as 
    m_hWnd is in the right place (that is, the first data member of the class) 
    and the HWND is, in fact, a handle to a tree control. It's the same reason 
    you can writepEdit = (CEdit*)GetDlgItem(ID_FOO);even though GetDlgItem returns a pointer to a CWnd, not a CEdit: because 
    CEdit is also a pure wrapper class, with no extra data or virtual functions 
    beyond what it inherits from CWnd.
    So the "almost any" in the statement "CCtrlView allows almost any control 
    to be a view" means specifically any control that adds no member data and 
    no virtual functions to CWnd, what I am calling a "pure wrapper class." If 
    your control class has its own data or virtual functions, you can't use 
    CCtrlView because the extra data/virtual functions won't exist in 
    CCtrlView/CView.
    For example, the first virtual function in CView is CView::IsSelected. If 
    your control class has some other virtual function, then things will 
    certainly bomb when you cast CCtrlView to your CFooCtrl and try to call 
    that virtual function. The function simply doesn't exist. Likewise, the 
    first data member in CView is m_pDocument. If your control class expects 
    some other data member, your code will bite the bag when it tries to access 
    it, if the object called is really a CCtrlView, not a CFooCtrl. Too bad, so 
    sad.
    In short, the only time you can use the CCtrlView trick is when your 
    CWnd-derived control class has no virtual functions and no member data of 
    its own. C'est la vie.
      

  13.   

    If you want to use your control in a doc/view app, what can you do—throw 
    your head on the table and weep? Of course not! Your first approach was 
    dandy: create your control as a child of the view and use OnSize to 
    position it exactly over the view's client area.CFooView::OnSize(..., cx, cy)
    {
      m_wndFooCtrl.SetWindowPos(NULL,
        0,0,cx,cy,SWP_NOZORDER);
    }Those input problems you encountered are easily overcome. Consider the 
    mouse. If you want to let the parent view handle mouse messages sent to 
    your control, the thing to do is abstract the messages into higher-level 
    events. That's a highfalutin way of saying something familiar to us all. 
    Consider, for example, a button. When the user clicks a button, the button 
    notifies its parent with a BN_CLICKED event. It does not send 
    WM_LBUTTONDOWN; it sends a WM_COMMAND message with subcode = BN_CLICKED. 
    The button is telling its parent window: the user clicked me. Likewise, 
    list controls don't broadcast WM_LBUTTONDOWN; they do a little processing 
    and notify their parents with LBN_SELCHANGE. (In the case of a 
    double-click, list controls do propagate LBN_DBLCLK, which is little more 
    than WM_LBUTTONDBLCK.) In general, the idea is that controls convert raw 
    events into higher-level events that are meaningful in the context of the 
    control.
    If you're doing this at home, you should probably use the more modern way, 
    which is WM_NOTIFY, instead of WM_COMMAND. WM_NOTIFY lets you pass a whole 
    struct of information instead of trying to squish everything into half a 
    DWORD. You can decide which mouse messages your control should propagate. 
    For example, buttons don't normally send BN_DOUBLECLICKED unless they have 
    the BS_NOTIFY style.
    So much for mousing. Now, what about the keyboard? That's even easier. When 
    the user activates your app by clicking on the caption or Alt-TABing to it, 
    Windows normally gives focus to the main frame. MFC, in turn, passes focus 
    to your view:void CFrameWnd::OnSetFocus(...)
    {
      if (m_pViewActive != NULL)
        m_pViewActive->SetFocus();
      else
        CWnd::OnSetFocus(...);
    }All you have to do is pass the focus, in turn, to your control:CFooView::OnSetFocus(...)
    {
      m_wndFooCtrl.SetFocus();
    }Now keystrokes go directly to your control. Do not pass view. I told you it 
    was easy! This is the age-old Windows way of doing things, but with all 
    those frameworks doing so much for you nowadays, it's easy to miss the 
    basics.
    The upshot is this: if your custom control view class is not a pure wrapper 
    function, that is, if it has so much as one data member or virtual function 
    of its own, then the way to convert your control into a view is to 
    instantiate it as a child window of the view and integrate it in three 
    simple steps.Handle WM_SIZE in the view to position your control exactly over the view's 
    client area.Convert mouse messages in the control to higher-level parent WM_NOTIFY 
    notifications.Handle WM_FOCUS in the view to set focus to your control.Incidentally—if I may be permitted to muse for just a paragraph or two—this
     example illustrates one of the drawbacks of the MFC object model, which 
    doesn't allow multiple inheritance. You can't say, "my class is a view and 
    a foo control," which is really what you want to do. It also shows why some 
    programmers may choose to implement custom controls using C only, and not 
    C++. It is possible, you know. All you have to do is register your own 
    window class (in the Windows sense), allocate a little memory block to hold 
    your window's instance data, and implement all your functions as messages—WM
    FOO_GETTHIS and WMFOO_SETTHAT. This was the only way to implement custom 
    controls before C++ came along, and it still has many benefits.
    For example, if you do it this way, some other C++ programmer could come 
    along and write a C++ pure wrapper class for your window, with simple 
    wrapper functions CFooCtrl::GetThis and CFooCtrl::SetThat, which merely 
    passed the parameters to and fro using the proper WMFOO_XXX messages, and 
    then such a programmer could in fact use CCtrlView to convert your control 
    to a view! Or, to put it differently, one way to use CCtrlView is to 
    reimplement your custom control using pure C and the Windows API with 
    messages and subclassing instead of MFC! This would require a bit more 
    typing and type-casting (for all those WPARAMs and LPARAMs), but would 
    leave you feeling satisfied and pure.
      

  14.   

    打字员给的内容,在MSDN的在线杂志上有,很精典很全面,这只是MFC玩的小猫腻。
      

  15.   

    这个问题以前bcpl回答过怀念bcpl一把具体什么原因楼上已经说清楚了:)
      

  16.   

    我觉得没什么不可以啊,就象
           class A
    {
    public:
    A(){
    a1=0;
    a2=0 ;} 
    ~A(){} 
    protected:
    private:
    int  a1,a2 ;
    };
    class B
    {
    public:
    B() {b1=1  ; b2=1 ; b3=1 ;}
    ~B(){}
    protected:
    private:
    int b1,b2,b3 ;};
    int main(int argc, char* argv[])
    {
    printf("Hello World!\n");
    A    a,*pa ;
    pa = &a ;
    B    b,*pb ;
    pb = &b ;
    pa =(A *)(void *)pb ; return 0;
    }
        可以得到两个不相干得类的信息,但是你自己要明白那个内存区是你要取得的内存区 。<可以把, {a1,a2}和{b1,b2} 看作是CListCtrl>
         以上个人理解