Frage: Klassen richtig einbinden



  • Guten Abend.

    Ich arbeite derzeit an einem kleinen Programm, einem Server, für den ich zwei Klassen habe.

    1.) MainFrame: Die eigentliche Fensterklasse

    #ifndef MAINFRAME_H
    #define MAINFRAME_H
    #include "wxcrafter.h"
    #include <wx/socket.h>
    #define MAX_CLIENTS 5
    
    //------------------------------------------------------------
    //------------------------------------------------------------
    // Klasse: MainFrame
    //------------------------------------------------------------
    //------------------------------------------------------------
    
    class MainFrame : public MainFrameBaseClass
    {
        public:
        MainFrame(wxWindow* parent);
        virtual ~MainFrame();
    
    	enum
    	{
    		SERVER_START,
    		SERVER_ID,
    		SOCKET_ID
    	};
    
    	public:
    	void OnServerStart( wxCommandEvent& WXUNUSED(event) );
    	void OnServerEvent( wxSocketEvent& WXUNUSED(event) );
    	void OnSocketEvent( wxSocketEvent& event );
    	void OnClientConnect( wxSocketEvent& event );
    
        protected:
    	virtual void OnButton2_closeButtonClicked(wxCommandEvent& event);
        virtual void OnButton1_startButtonClicked(wxCommandEvent& event);
    
    	wxSocketBase *m_ClientSockets[MAX_CLIENTS];
    	wxSocketServer *m_pSocketServer;
    	ClientThread *m_pClientThread;
    	wxCriticalSection m_csClientThreadCS;
    
    	friend class ClientThread;
    
    	DECLARE_EVENT_TABLE();
    };
    #endif // MAINFRAME_H
    
    #include "MainFrame.h"
    #include <wx/msgdlg.h>
    #include <wx/log.h> 
    
    //------------------------------------------------------------
    //------------------------------------------------------------
    // Klasse: MainFrame
    //------------------------------------------------------------
    //------------------------------------------------------------
    
    MainFrame::MainFrame(wxWindow* parent)
        : MainFrameBaseClass(parent)
    {
       m_pSocketServer = 0;
    
       for ( int i = 0; i < MAX_CLIENTS; i++ )
       {
    	   m_ClientSockets[i] = 0;
       }
    }
    
    MainFrame::~MainFrame()
    {
    
    }
    
    void MainFrame::OnButton1_startButtonClicked( wxCommandEvent& event )
    {	
    	OnServerStart( event );
    }
    
    void MainFrame::OnButton2_closeButtonClicked( wxCommandEvent& event )
    {
    	Close( true );
    }
    
    BEGIN_EVENT_TABLE(MainFrame, wxFrame)
       EVT_BUTTON(SERVER_START, MainFrame::OnServerStart)
       EVT_SOCKET(SERVER_ID, MainFrame::OnServerEvent)
       EVT_SOCKET(SOCKET_ID, MainFrame::OnSocketEvent)
    END_EVENT_TABLE()
    
    void MainFrame::OnServerStart( wxCommandEvent& WXUNUSED(event) )
    {
    	wxIPV4address addr;
    
    	try
    	{
    		// Create the address
    		addr.Hostname( m_textCtrl1_IP -> GetValue() );
    		addr.Service( m_textCtrl2_Port -> GetValue() );
    
    		// Create the socket
    		m_pSocketServer = new wxSocketServer( addr );
    
    		// Check if the server is listening
    		if ( !m_pSocketServer -> IsOk() )
    		{
    		   return;	
    		}
    
    		// Set up the event handler
    		m_pSocketServer -> SetEventHandler( *this, SERVER_ID );
    		m_pSocketServer -> SetNotify( wxSOCKET_CONNECTION_FLAG );
    		m_pSocketServer -> Notify( true );
    	}
    	catch (...)
    	{
    
    	}
    }
    
    void MainFrame::OnServerEvent( wxSocketEvent& WXUNUSED(event) )
    {	
    	try
    	{
    		// Check the array if a free Socket is available
    		for ( int i = 0; i < MAX_CLIENTS; i++ )
    		{
    			if ( m_ClientSockets[i] == 0 )
    			{
    				m_ClientSockets[i] = new wxSocketBase();
    			}
    
    			if ( m_ClientSockets[i] -> IsDisconnected() )
    			{
    			   // Accept the new conncetion and get the socket pointer
    			   m_ClientSockets[i] = m_pSocketServer -> Accept( true );
    
    			   // Tell the new socket how and where to process its events
    		       m_ClientSockets[i] -> SetEventHandler( *this, SOCKET_ID );
    		       m_ClientSockets[i] -> SetNotify( wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG );
    		       m_ClientSockets[i] -> Notify( true );
    			   break;	
    			}
    		}
    	}
    	catch (...)
    	{
    
    	}
    }
    
    void MainFrame::OnSocketEvent( wxSocketEvent& event )
    {	
    	try
    	{
    	   m_pClientThread = new ClientThread( this );
    
    	   if ( m_pClientThread -> Run() != wxTHREAD_NO_ERROR )
    	   {
    		   wxLogError( "Can't create the thread!" );
    		   delete m_pClientThread;
    		   m_pClientThread = NULL;
    	   }
    	}
    	catch (...)
    	{
    
    	}
    }
    
    void MainFrame::OnClientConnect( wxSocketEvent& event )
    {
    	wxSocketBase *pSocket = 0;
    	wxString IP;
    	wxIPV4address addr;
    	char buffer[50];
    
    	try
    	{
    		// The socket that had the event
    		pSocket = event.GetSocket();
    
    		// Handle the socket events
    		switch ( event.GetSocketEvent() )
    		{
    		   case wxSOCKET_INPUT: 
    				m_pSocketServer -> GetPeer( addr );
    				IP = addr.Hostname();
    				m_richTextCtrl_Client_List -> AppendText( IP );
                    buffer[0] = 'H';
    				buffer[1] = 'i';
    				buffer[2] = '\0';
    				pSocket -> Write( buffer, sizeof( buffer ) ); break;
    		   case wxSOCKET_LOST: 
    			    m_richTextCtrl_Client_List -> Clear();
    				pSocket -> Destroy(); break;
    		}
    	}
    	catch (...)
    	{
    
    	}	
    }
    

    2.) ClientThread: Eine Klasse für Threads zum bearbeiten von Client-Anfragen (Bei Threads bin ich aber noch am einlesen 😉 )

    #ifndef CLIENT_THREAD_H
    #define CLIENT_THREAD_H
    #include <wx/thread.h>
    
    //------------------------------------------------------------
    //------------------------------------------------------------
    // Klasse: ClientThread
    //------------------------------------------------------------
    //------------------------------------------------------------
    
    class ClientThread : public wxThread
    {	
       public:
       ClientThread( MainFrame *pHandler );
       ~ClientThread();	
    
       protected:
       virtual wxThread::ExitCode Entry();
       MainFrame *m_pHandler;
    };
    #endif // CLIENT_THREAD_H
    
    #include "ClientThread.h"
    
    //------------------------------------------------------------
    //------------------------------------------------------------
    // Klasse: ClientThread
    //------------------------------------------------------------
    //------------------------------------------------------------
    
    ClientThread::ClientThread
    ( MainFrame *pHandler ) :
       m_pHandler( pHandler )
    {
    
    }
    
    ClientThread::~ClientThread()
    {
    	wxCriticalSectionLocker enter( m_pHandler -> m_csClientThreadCS );
       	m_pHandler -> m_pClientThread = NULL;
    }
    
    wxThread::ExitCode ClientThread::Entry()
    {	
    	//m_pHandler -> OnClientConnect()
    
    	return 0;
    }
    

    Mein Problem ist jetzt wie folgt:
    Beide Klassen besitzen in der jeweiligen Header-Datei eine Membervariable vom jeweils anderen Typ.

    MainFrame => ClientThread *m_pClientThread;
    ClientThread => MainFrame *m_pHandler;

    Ich kann aber hier in diesem Fall ja nicht einfach die Header-Dateien includieren, da die "ClientThread.h" und die "MainFrame.h" bereits von den CPP-Dateien includiert werden. Die Include-Guards lassen das ja nicht zu.

    Deshalb bekomme ich derzeit beim Übersetzen den Fehler:
    "MainFrame.h:38:2: error: ClientThread does not name a type"

    Wie löse ich das am Besten? Es tut mir Leid, wenn ich mich dumm anstelle - Ich hoffe, ihr könnt mir helfen. PS: Mein erster Post im Forum ^^.



  • Das geht mit Vorwärtsdeklarationen. Der Typ ist damit zwar noch nicht definiert, aber dem Compiler bekanntgegeben, sodass du Zeiger und Referenzen auf diesen Typ erstellen kannst. Zum instanziieren braucht der Compiler aber die konkrete Definition.



  • Wie sehe das dann richtig aus?
    Bzw. wo muss ich das dann am Besten machen?

    In MainFrame:

    #ifndef MAINFRAME_H
    #define MAINFRAME_H
    #include "wxcrafter.h"
    #include <wx/socket.h>
    #define MAX_CLIENTS 5
    class ClientThread;
    
    //------------------------------------------------------------
    //------------------------------------------------------------
    // Klasse: MainFrame
    //------------------------------------------------------------
    //------------------------------------------------------------
    
    class MainFrame : public MainFrameBaseClass
    {
        public:
        MainFrame(wxWindow* parent);
        virtual ~MainFrame();
    
        enum
        {
            SERVER_START,
            SERVER_ID,
            SOCKET_ID
        };
    
        public:
        void OnServerStart( wxCommandEvent& WXUNUSED(event) );
        void OnServerEvent( wxSocketEvent& WXUNUSED(event) );
        void OnSocketEvent( wxSocketEvent& event );
        void OnClientConnect( wxSocketEvent& event );
    
        protected:
        virtual void OnButton2_closeButtonClicked(wxCommandEvent& event);
        virtual void OnButton1_startButtonClicked(wxCommandEvent& event);
    
        wxSocketBase *m_ClientSockets[MAX_CLIENTS];
        wxSocketServer *m_pSocketServer;
        ClientThread *m_pClientThread;
        wxCriticalSection m_csClientThreadCS;
    
        friend class ClientThread;
    
        DECLARE_EVENT_TABLE();
    };
    #endif // MAINFRAME_H
    

    oder in ClientThread:

    #ifndef CLIENT_THREAD_H
    #define CLIENT_THREAD_H
    #include <wx/thread.h>
    class MainFrame;
    
    //------------------------------------------------------------
    //------------------------------------------------------------
    // Klasse: ClientThread
    //------------------------------------------------------------
    //------------------------------------------------------------
    
    class ClientThread : public wxThread
    {  
       public:
       ClientThread( MainFrame *pHandler );
       ~ClientThread();
    
       protected:
       virtual wxThread::ExitCode Entry();
       MainFrame *m_pHandler;
    };
    #endif // CLIENT_THREAD_H
    

    Oder in beiden? Und was heißt dann genau "konkrete Definition"?





  • Haio schrieb:

    Wie sehe das dann richtig aus?
    Bzw. wo muss ich das dann am Besten machen?

    Hast du schon richtig gemacht. Man muss es in mindestens einer Header Datei machen aber beide schadet auch nicht. Es hat sogar eher Vorteile, da weniger Header mit in die gleiche Compilation Unit gezogen werden und sich Compilezeiten verbessern können. Einziger Nachteil wäre wenn man von außen an die Pointer kommt (weil public oder durch eine Memberfunktion) weil man dann an diesen Stellen auch manuell den zweiten Header includen muss. Für private/protected Membervariablen die Pointer auf eigene Klassen sind finde ich es eine gute Angewohnheit einfach immer eine Forward Declaration zu nutzen.

    Haio schrieb:

    Und was heißt dann genau "konkrete Definition"?

    class X;  // Vorwärtsdeklaration
    
    class X  // konkrete Definition
    {
      // Stuff
    };
    

Log in to reply