2016-09-13 12 views
0

CONTROL.CPPを見ると、CONTROL :: CONTROLNATIVEWINDOW :: WndProc()が表示されます。ここでは、テストのためにCONTROL名を出力しています。 GetName()メソッドをオーバーライドするCONTROLの複数の派生クラスがあります。ただし、TEXTBOXも出力する必要があるにもかかわらず、これまでに出力された唯一の派生クラスはWINDOWです。なぜWndProcのキャストが正しくないのですか?

私は何を言うことができないことであるLRESULT CALLBACK InternalWinProc(中reinterpret_castはは)間違って鋳造された場合:

LRESULT CALLBACK InternalWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 
{ 
    NativeWindow* window = reinterpret_cast<NativeWindow*>(GetWindowLongPtr(hWnd, GWLP_USERDATA)); 
    if (window) { 
     Message msg = Message::Create(hWnd, message, IntPtr((void*)wParam), IntPtr((void*)lParam)); 
     window->WndProc(&msg); 
    } 

    return DefWindowProc(hWnd, message, wParam, lParam); 
} 

あるいは、ライン

window = new ControlNativeWindow(this); 

を基本クラスCONTROLにコンストラクタは派生型を正しく保存していません。

デバッガを実行して上の行を見ると、これはそれぞれの派生クラスの代わりに、すべてがCONTROL :: ...メソッドを指すvptrを持っています。これは私がやっているような基本クラスのこの派生クラスのポインタを保存することはできないと思います。

そして、私はInternalWndProc機能でNativeWindowの*に戻ってそれをキャストするために行くときに、ライン

control->GetName(); 

Control::ControlNativeWindow::WndProc(Message * msg) 

方法で実行されるときに、それはそんなに悪いキャストを与えていること誤っ

Window::GetName(); 

を呼んでいます

CONTROL.H

#ifndef CONTROL_H 
#define CONTROL_H 

#include "IntPtr.h" 
#include "CreateParams.h" 
#include "Point.h" 
#include "Size.h" 

#include "NativeWindow.h" 

class Control 
{ 
public: 
    Control(); 

    ~Control(); 

    virtual void CreateControl(); 

    Control* GetParent() { return parent; } 
    void SetParent(Control* parent) { this->parent = parent; } 

    IntPtr GetHandle() { return window->GetHandle(); } 

    Point GetLocation() { return Point(x, y); } 
    void SetLocation(Point point); 

    Size GetSize() { return Size(width, height); } 
    void SetSize(Size size); 

    std::string GetText(); 
    void SetText(std::string text); 

    void Show(); 

    bool IsHandledCreated(); 

    class ControlNativeWindow : public NativeWindow 
    { 
    public: 
     ControlNativeWindow(Control* control); 
     virtual std::string GetName() { return "CONTROLNATIVEWindow\n"; } 
    protected: 
     virtual void WndProc(Message* msg); 

    private: 
     Control* control; 
    }; 

    virtual std::string GetName() { return "Control\n"; } 

protected: 

    virtual void OnPaint(); 
    virtual void OnTextChanged(); 

    virtual void DefWndProc(Message* msg); 
    virtual void WndProc(Message* msg); 

    virtual void CreateHandle(); 

    virtual CreateParams GetCreateParams(); 

private: 

    Control* parent; 

    ControlNativeWindow* window; 

    int x; 
    int y; 
    int width; 
    int height; 

    std::string text; 

    bool visible; 
}; 

#endif // CONTROL_H 

CONTROL.CPP

#include "Control.h" 
#include "Utility.h" 
#include <string> 

#include "Message.h" 

using namespace std; 

Control::Control() 
    : x(0), y(0), 
    width(200), height(20), // fix this 
    visible(false) 
{ 
    window = new ControlNativeWindow(this); 
} 

Control::~Control() 
{ 
} 

void Control::CreateControl() 
{ 
    CreateHandle(); 
} 

void Control::SetLocation(Point point) 
{ 
    x = point.X; 
    y = point.Y; 
} 

void Control::SetSize(Size size) 
{ 
    width = size.Width; 
    height = size.Height; 
} 

std::string Control::GetText() 
{ 
    if (IsHandledCreated()) 
    { 
     HWND hWnd = (HWND)GetHandle().ToPointer(); 
     int len = GetWindowTextLength(hWnd); 

     wchar_t* str = new wchar_t[len + 1]; // fix 
     GetWindowText(hWnd, str, len); 

     return string(WStringToAnsi(str)); 
    } 

    return text; 
} 

void Control::SetText(string text) 
{ 
    if (IsHandledCreated()) 
    { 
     wstring str = AnsiToWString(text); 
     SetWindowText((HWND)GetHandle().ToPointer(), str.c_str()); 
    } 

    this->text = text; 
} 

void Control::Show() 
{ 
    visible = true; 
} 

bool Control::IsHandledCreated() 
{ 
    return window->GetHandle() == IntPtr::Zero; 
} 

void Control::OnPaint() 
{ 
} 

void Control::OnTextChanged() 
{ 
} 

void Control::DefWndProc(Message * msg) 
{ 
    window->DefWndProc(msg); 
} 

void Control::WndProc(Message * msg) 
{ 
    switch (msg->Msg) 
    { 
    case WM_PAINT: 
     OnPaint(); 
     break; 

    case WM_DESTROY: 
     PostQuitMessage(0); 

    default: 
     DefWndProc(msg); 
    }; 
} 

void Control::CreateHandle() 
{ 
    CreateParams cp = GetCreateParams(); 

    SetLocation(Point(cp.GetX(), cp.GetY())); 

    window->CreateHandle(&cp); 
} 

CreateParams Control::GetCreateParams() 
{ 
    CreateParams cp; 
    cp.SetParent(parent->GetHandle()); 
    cp.SetCaption(text); 
    return cp; 
} 

Control::ControlNativeWindow::ControlNativeWindow(Control* control) 
{ 
    wstring ws = AnsiToWString(control->GetName()); 
    OutputDebugString(ws.c_str()); 
    this->control = static_cast<Control*>(control); 
    ws = AnsiToWString(this->control->GetName()); 
    OutputDebugString(ws.c_str()); 
} 

void Control::ControlNativeWindow::WndProc(Message * msg) 
{ 
    // HERE IS THE ISSUE 
    // IT IS OUTPUTTING WINDOW ALWAYS 
    // HOWEVER, IT SHOULD OUTPUT THE CORRECT DERIVED CLASS 
    wstring ws = AnsiToWString(control->GetName()); 
    OutputDebugString(ws.c_str()); 
    control->WndProc(msg); 
} 

NATIVEWINDOW.H

#ifndef NATIVE_WINDOW_H 
#define NATIVE_WINDOW_H 

#include <string> 
#include "IntPtr.h" 

class CreateParams; 
class Message; 

class NativeWindow 
{ 
public: 
    NativeWindow(); 
    ~NativeWindow(); 

    virtual void CreateHandle(CreateParams* cp); 

    IntPtr GetHandle() { return handle; } 

    virtual void DefWndProc(Message* msg); 
    virtual void WndProc(Message* msg); 

    virtual std::string GetName() { return "NATIVEWindow\n"; } 

private: 
    IntPtr handle; 

    class WindowClass 
    { 
    public: 
     WindowClass(std::string className, int classStyle); 

     std::string GetClsName() { return className; } 
     int GetClassStyle() { return classStyle; } 

    private: 
     void registerClass(); 

     friend NativeWindow; 
     NativeWindow* targetWindow; 

     std::string className; 
     int classStyle; 
    }; 
}; 

#endif // NATIVE_WINDOW_H 
:ここ

は、コードの残りの部分であります

NATIVEWINDOW.CPP

#include "NativeWindow.h" 
#include <Windows.h> 
#include <string> 
#include "CreateParams.h" 
#include "Message.h" 
#include "Utility.h" 

using namespace std; 

LRESULT CALLBACK InternalWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); 

NativeWindow::NativeWindow() : handle(IntPtr::Zero) 
{ 
} 

NativeWindow::~NativeWindow() 
{ 
} 

void NativeWindow::CreateHandle(CreateParams* cp) 
{ 
    WindowClass windowClass(cp->GetClsName(), cp->GetClassStyle()); 

    wstring wideClassName = AnsiToWString(windowClass.GetClsName()); 
    wstring wideCaption = AnsiToWString(cp->GetCaption()); 

    HWND hWnd = CreateWindowEx(
     cp->GetExStyle(), 
     wideClassName.c_str(), 
     wideCaption.c_str(), 
     cp->GetStyle(), 
     cp->GetX(), cp->GetY(), 
     cp->GetWidth(), cp->GetHeight(), 
     (HWND)cp->GetParent().ToPointer(), 
     nullptr, 
     nullptr, 
     nullptr 
    ); 

    if (!hWnd) 
    { 
     MessageBox(nullptr, L"Call to CreateWindow Failed", L"FAIL", MB_OK); 
     return; 
    } 

    handle = hWnd; 
    windowClass.targetWindow = this; 

    SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)this); 
} 

void NativeWindow::WndProc(Message* msg) 
{ 
    DefWndProc(msg); 
} 

void NativeWindow::DefWndProc(Message * msg) 
{ 
    DefWindowProc((HWND)msg->HWnd.ToPointer(), (LRESULT)msg->Result.ToPointer(), (WPARAM)msg->WParam.ToPointer(), (LPARAM)msg->LParam.ToPointer()); 
} 

NativeWindow::WindowClass::WindowClass(std::string className, int classStyle) 
{ 
    this->className = className; 
    this->classStyle = classStyle; 
    registerClass(); 
} 

void NativeWindow::WindowClass::registerClass() 
{ 
    WNDCLASSEX wndclass; 
    wndclass.cbSize = sizeof(WNDCLASSEX); 
    wndclass.style = classStyle; 
    wndclass.lpfnWndProc = InternalWndProc; 
    wndclass.cbClsExtra = 0; 
    wndclass.cbWndExtra = 0; 
    wndclass.hInstance = nullptr; 
    wndclass.hIcon = LoadIcon(nullptr, MAKEINTRESOURCE(IDI_APPLICATION)); 
    wndclass.hCursor = LoadCursor(nullptr, IDC_ARROW); 
    wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); 
    wndclass.lpszMenuName = nullptr; 
    wstring ws = AnsiToWString(className); 
    wndclass.lpszClassName = ws.c_str(); 
    wndclass.hIconSm = LoadIcon(nullptr, MAKEINTRESOURCE(IDI_APPLICATION)); 

    WNDCLASSEX wcex; 
    wcex.lpszClassName = ws.c_str(); 

    bool found = GetClassInfoEx(nullptr, ws.c_str(), &wcex); 
    if (found) 
     return; 

    if (!RegisterClassEx(&wndclass)) 
    { 
     DWORD dw = GetLastError(); 

     if (dw == ERROR_CLASS_ALREADY_EXISTS) 
     { 
      MessageBox(nullptr, L"Class already exists", L"SUCCESS", MB_OK); 
     } 
     else 
     { 
      MessageBox(nullptr, L"Call to RegisterClassEx Failed", L"FAIL", MB_OK); 
     } 
    } 
} 

LRESULT CALLBACK InternalWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 
{ 
    NativeWindow* window = reinterpret_cast<NativeWindow*>(GetWindowLongPtr(hWnd, GWLP_USERDATA)); 
    if (window) { 
     Message msg = Message::Create(hWnd, message, IntPtr((void*)wParam), IntPtr((void*)lParam)); 
     window->WndProc(&msg); 
    } 

    return DefWindowProc(hWnd, message, wParam, lParam); 
} 

WINDOW.H

#ifndef WINDOW_H 
#define WINDOW_H 

#include <Windows.h> 
#include "Control.h" 
#include "ControlCollection.h" 

class Window : public Control 
{ 
public: 
    Window(); 
    ~Window(); 

    void Show(); 

    virtual std::string GetName() { return "Window\n"; } 

protected: 
    virtual CreateParams GetCreateParams(); 

private: 
    ControlCollection controls; 
}; 

#endif // WINDOW_H 

TEXTBOX.H

#ifndef TEXTBOX_H 
#define TEXTBOX_H 

#include "Control.h" 

class TextBox : public Control 
{ 
public: 
    TextBox(); 
    ~TextBox(); 

    virtual std::string GetName() { return "TextBox\n"; } 

protected: 

    virtual void WndProc(Message* msg); 

    virtual void OnTextChanged(); 

    virtual CreateParams GetCreateParams(); 

private: 
    void reflectCommand(Message* msg); 
}; 

#endif // TEXTBOX_H 
+0

これはコードの壁ですが、あなたが示すコードに関する2つの観察は面倒かもしれません。 (1)それは 'window-> WndProc(&msg);')から値を返しません。(2)それ以降、デフォルトのハンドリングを常に呼び出すようになりましたし、Windows APIは[SetWindowSubclass'](https: //msdn.microsoft.com/en-us/library/windows/desktop/bb762102(v=vs.85).aspx)。 –

+0

ありがとう@Alf、これはどのように動作するはずです。これはC#.NET – keelerjr12

+0

ウィンドウを表す* 2つのクラスがあり、それらは関連していません。他のクラスのためのメッセージハンドラでのキャストは失敗することになります。 NativeWindowはその継承スキームに参加していません。継承スキームには参加しません。継承されず常にラップされます。カプセル化と抽象化の大きな違い –

答えて

2
由来のメンバーになることはない

A C++オブジェクト基本クラスのconstructorの後までクラスを継承rが終了する。要するに、オブジェクトは、コントロールコンストラクタが離れるまで、テキストボックス型ではありません。

class A { public: A() x() { doit(); } virtual void doit(); private: int x; } 

と派生クラス:

はvtableのを持つオブジェクトを考えてみましょうAのコンストラクタ本体に入ると

class B { public: virtual void doit(); private: std::string myname; } 

ABオブジェクトは、このようなものです:

+--------------------+ 
| A vtable   | // A vtable 
+--------------------+ 
| int x    | // A's member (0 from initializer list) 
+--------------------+ 
| std::string myname | // B's member (uninit) 
+--------------------+ 

。なお、 B :: doit()が実行されると、初期化されていないmynameにアクセスします。

Bのコンストラクタは、vtableポインタをB vtableに再割り当てし、mynameのコンストラクタを実行しますが、これは既にAコンストラクタ本体を実行した後です。 Javaでは、リフレクションでオブジェクトが実行時に型を変更しないようにする必要があるため、これとは異なります。

したがって、オブジェクトの仮想メソッドの1つを呼び出すと、派生型のオーバーライドはまだ参照されません。

多くの場合、オブジェクトは、派生したクラスを初期化に参加させるために、ユーザーが作成後に使用する必要がある種類のメソッドを持っています。

+0

同じことが純粋な仮想関数に適用されますか? – andlabs

+1

はい。純粋仮想メソッドは、メソッドを提供するクラスの構築の開始時までstd :: terminateを呼び出す関数を指すことになっています。 –

+0

ああ、私は今これを覚えています。それは少しです。ありがとうございました! – keelerjr12

関連する問題