Klassendesign



  • Abend jungs

    Ich habe folgende Klassen:

    #if! defined(windowobject_hpp_included)
    #define windowobject_hpp_included
    
    #include <Windows.h>
    #include <WindowsX.h>
    #include <iostream>
    
    class WindowObject
    {
    protected:
    	::HWND window_handle_;
    
    public:
    	// Standard Konstruktor
    	WindowObject(void);
    
    	// Verarbeitet Nachrichten dieses Fensters
    	virtual ::LRESULT __stdcall window_procedure(::HWND handle, ::UINT message, ::WPARAM w_param, ::LPARAM l_param);
    	// Verarbeitet Nachrichten aller Fenster
    	::LRESULT static message_receiver(::HWND handle, ::UINT message, ::WPARAM w_param, ::LPARAM l_param);
    
    	// setzt aktuelle Fenster Handle
    	void	set_window_handle(::HWND handle);
    	// ermittelt aktuelle Fenster Handle
    	::HWND	get_window_handle(void) const; 
    
    	static WindowObject* get_object_from_window(::HWND handle);
    
    	// erzeugt Fenster
    	virtual bool create(const std::basic_string<wchar_t>& class_name, 
    						const std::basic_string<wchar_t>& caption, 
    						long x, long y, long width, long height,
    						long style, long style_ex,
    						::HWND parent = 0) = 0;
    
    	void show	(void);
    	void hide	(void);
    	void enable	(void);
    	void disable(void);
    };
    
    #endif
    
    #if! defined(control_hpp_included)
    #define control_hpp_included
    
    #include "WindowObject.hpp"
    
    class Control : public WindowObject
    {
    protected:
    	bool create(const std::basic_string<wchar_t>& class_name, 
    				const std::basic_string<wchar_t>& caption, 
    				long x, long y, long width, long height,
    				long style, long style_ex,
    				::HWND parent = 0);
    
    public:
    	Control(void);
    };
    
    #endif
    
    #if! defined(button_hpp_included)
    #define button_hpp_included
    
    #include "Control.hpp"
    
    class Button : public Control
    {
    public:
    	virtual bool create(const std::basic_string<wchar_t>& window_text, 
    						long x, long y, long width, long height,
    						long style, long style_ex,
    						HWND parent = 0);
    };
    
    #endif
    
    #include "Control.hpp"
    
    //-----------------------------------------------------------------------//
    // PUBLIC
    //
    // 
    //-----------------------------------------------------------------------//
    Control::Control(void) : WindowObject()
    {
    
    }
    
    //-----------------------------------------------------------------------//
    // PROTECTED
    //
    // 
    //-----------------------------------------------------------------------//
    bool Control::create(const std::basic_string<wchar_t>& class_name, 
    					 const std::basic_string<wchar_t>& caption, 
    					 long x, long y, long width, long height,
    					 long style, long style_ex,
    					 ::HWND parent)
    {
    	// Control erzeugen
    	window_handle_ = ::CreateWindowEx(style_ex, 
    									  class_name.c_str(),
    									  caption.c_str(), 
    									  style,
    									  x, y, width, height, 
    									  parent, 0,
    									  ::GetModuleHandle(0), this);
    	if(window_handle_)
    		return(true);
    	return(false);
    }
    
    #include "Button.hpp"
    
    //-----------------------------------------------------------------------//
    // PUBLIC
    //
    // 
    //-----------------------------------------------------------------------//
    bool Button::create(const std::basic_string<wchar_t>& window_text, 
    					long x, long y, long width, long height, 
    					long style, long style_ex, 
    					HWND parent)
    {
    	if(Control::create(L"button", window_text, x, y, width, height, style, style_ex, parent))
    		return(true);
    	return(false);
    }
    

    Beim Aufruf von:

    WindowObject* win = new Window();
    	WindowObject* button = new Button();
    
    	win->create(L"buttonx", L"test", 0, 0, 100, 200, WS_OVERLAPPEDWINDOW, WS_EX_APPWINDOW, 0);
    	win->show();
    
    	button->create(L"hallo", 10, 10, 50, 20, 0, 0, win->get_window_handle());
    

    kommt mir nun unlogischerweise folgender Fehler:

    error C2664: 'WindowObject::create': Konvertierung des Parameters 2 von 'int' in 'const std::basic_string<_Elem,_Traits,_Ax> &' nicht möglich
    1>        with
    1>        [
    1>            _Elem=wchar_t,
    1>            _Traits=std::char_traits<wchar_t>,
    1>            _Ax=std::allocator<wchar_t>
    1>        ]
    1>        Ursache: Konvertierung von 'int' in 'const std::basic_string<_Elem,_Traits,_Ax>' nicht möglich
    1>        with
    1>        [
    1>            _Elem=wchar_t,
    1>            _Traits=std::char_traits<wchar_t>,
    1>            _Ax=std::allocator<wchar_t>
    1>        ]
    1>        Quelltyp konnte von keinem Konstruktor angenommen werden, oder die Überladungsauflösung des Konstruktors ist mehrdeutig
    

    Warum nimmt der hier die create-Funktion der Control Klasse?

    button->create(L"hallo", 10, 10, 50, 20, 0, 0, win->get_window_handle());
    

    Wie kann ich das Problem umgehen?

    mfg



  • Achso, ich möchte das Problem so umgehen, dass ich weiterhin die Bezeichnung create nutzen kann.



  • Hi,

    dein Button::Create ist eine neue virtuelle Funktion, da sie verschiedene Parameter hat, als die der Klasse drüber. Deswegen werden diese nicht überschrieben.

    Dein Compiler sieht die Variable button als WinO* und versucht dann über die vtable die passende überschriebene Funktion in Button zu finden. Doch gibt es dort so eine Funktion nicht und er muss auf die in WinO ausweichen.

    Dir bleibt nichts anderes übrig, um das polymorphe Verhalten beizubehalten, create in Button auch mit der selben Signatur zu definieren.

    Was besser weiß ich nicht 🙂

    Edit: Oder boost::variant als zweiten Parameter verwenden oder was selbst dafür basteln.



  • Der Compiler sieht beim Compilieren nur den statischen Typ von button, und der ist vom Typ WindowObject . Deshalb kann der Compiler dafuer auch nur die Funktionen akzeptieren, die WindowObject bereitstellt. Um das zu umgehen, kannst du einen dynamic_cast<> auf Button* versuchen, was allerdings in dem Fall kein schoener Stil waere, oder die Polymorphie richtig nutzen, indem du die virtuellen Funktionen in den abgeleiteten Klassen mit gleicher Signatur ueberlaedst.

    Abgesehen davon kommt mir das Design von WindowObject etwas kaputt vor: du erstellst mit dem Standardkonstruktor ein WindowObject ohne wirkliche Eigenschaften und versuchst die dann mit create() zu setzen. Das klingt son bisschen nach absichtlicher Totgeburt mit folgender Reanimation. Die Sache ist doch allgemein die:
    Wenn ein Objekt nicht richtig erstellt werden kann, kann man es auch nicht nutzen. In deinem Fall bedeutet das vermutlich, dass create() dir ein false zurueckgibt (reanimation fehlgeschlagen) und du lebst mit einem Untoten WindowObject weiter, dem nur noch ein delete() hilft. Gerade wenn eine Klasse mehrere Member hat, weiss man dann oft nicht mehr genau, welche davon konstruiert wurden und wieder zerstoert wrden muessen, und bei welchen create() gescheitert ist. Einfacher ist folgendes: Verlege die Funktionalitaet von create() in den Konstruktor. Wenn das Erzeugen des Objekts fehlschlaegt, loese eine Exception aus. Dann wird zuerst alels was bis dahin schon erzeugt wurde an Membern wieder zerstoert, und wenn die Ueberbleibsel der vergeblichen Objektkonstruktion abgeraeumt sind, wird die Exception an die Funktion weitergereicht, die versucht hat, das WindowObject zu erstellen. Du bist dann genauso ungluecklich wie vorher (hast naemlich kein Fenster erstellen koennen udn musst irgendwie damit umgehn, z.B. indem du die Exception durchfliegen laesst und das Programm abbrichst), musst dich aber nicht mehr mit dem halbfertigen Fensterzombie rumschlagen.
    Fuer den Fall, dass Teile des Objektes optionale Komponenten sind, erzeuge die mittels Pointern. Wenn die Konstruktion der Komponente fehlschlaegt setz den Pointer auf 0 und gut ists.


Anmelden zum Antworten