C++ Klassenhilfstool. nützlich, oder gibts das schon?



  • Hi!

    Wäre es nicht schön, einfach mit einen Klassenassistenten ne komplette Klasse mit Klicks zu erstellen? Naja, das is ja noch nich so doll, aber nun kommts. :p
    Es wird auch automatisch eine Handle-Klasse erstellt!

    Ungefähr so stell ich mir das vor:
    Es gibt so eine Schema-Datei. Das ist C++ mit ein paar Zusatz-"Funktionen".

    ##. das is kommentar
    
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    ///
    /// FILENAME:   <!CLASSNAME!>.h
    /// DESCRIPTION:<!DESCRIPTION!>
    /// VERSION:    0.01
    ///
    /// COPYRIGHT:  Copyright (C) <!YEAR!> by <!AUTHOR!>, <!COMPANY!> (R)
    ///
    
    ///
    /// HISTORY
    ///
    /// DATE        | AUTHOR        | CHANGE
    /// <!DATE!>    <!AUTHOR!>    File created
    ///
    ///
    
    ##UPPER_BEGIN##
    #ifndef _<!CLASSNAME!>_H_
    #define _<!CLASSNAME!>_H_
    ##UPPER_END##
    
    namespace <!NAMESPACE!>
    {
    
    ##TEMPLATECLASS_BEGIN##
        template<<!TEMPLATECLASS_LIST!>>
    ##TEMPLATECLASS_END##
        class <!CLASSNAME!> 
    ##BASECLASS_BEGIN##
            : <!BASECLASS_LIST!>
    ##BASECLASS_END##
        {
        public:
    
    ##PUBLIC_FUNCTIONS_START##
            <!RETURNTYPE!> <!FUNCTIONNAME!>(<!PARAMETER_LIST!> );
    ##PUBLIC_FUNCTIONS_END##
    
        protected:
    
    ##PROTECTED_FUNCTIONS_START##
            <!RETURNTYPE!> <!FUNCTIONNAME!>(<!PARAMETER_LIST!> );
    ##PROTECTED_FUNCTIONS_END##
    
    ##PROTECTED_VARIABLES_START##
            <!VARIABLE_TYPE!> <!VARIABLE_NAME!>;
    ##PROTECTED_VARIABLES_END##
    
        private:
    
    ##PRIVATE_FUNCTIONS_START##
            <!RETURNTYPE!> <!FUNCTIONNAME!>(<!PARAMETER_LIST!> );
    ##PRIVATE_FUNCTIONS_END##
    
    ##PRIVATE_VARIABLES_START##
            <!VARIABLE_TYPE!> <!VARIABLE_NAME!>;
    ##PRIVATE_VARIABLES_END##
    
        }; // class <!CLASSNAME!>
    }; // namespace <!NAMESPACE!>
    
    #endif
    
    --------------------------------------------------------------------------------- CPP SOURCE
    
    #include "<!CLASSNAME!>.h"
    
    ##PUBLIC_FUNCTIONS_START##
    //////////////////////////////////////////////////////////////////////////
    //
    // <!FUNCTIONNAME!>
    //
    //   <!DESCRIPTION!>
    //
    // Last change: <!DATE!>, <!AUTHOR!>
    //
    <!RETURNTYPE!> <!CLASSNAME!>::<!FUNCTIONNAME!>(<!PARAMETER_LIST!> )
    {
        <!SOURCECODE!>
    }
    
    ##PUBLIC_FUNCTIONS_END##
    
    --------------------------------------------------------------------------------- HandleClass Source
    
    #include "<!CLASSNAME!>.h"
    #include "I<!CLASSNAME!>.h"
    
    ##PUBLIC_FUNCTIONS_START##
    //////////////////////////////////////////////////////////////////////////
    //
    // <!FUNCTIONNAME!>
    //
    //   <!DESCRIPTION!>
    //
    // Last change: <!DATE!>, <!AUTHOR!>
    //
    <!RETURNTYPE!> I<!CLASSNAME!>::<!FUNCTIONNAME!>(<!PARAMETER_LIST!> )
    {
        return(m_data-><!FUNCTIONNAME!>(<!PARAMETER_NOTYPE!> ));
    }
    
    ##PUBLIC_FUNCTIONS_END##
    

    Mein Programm läuft diese Datei also durch und ersetzt, z.b. <!CLASSNAME!> zu TestClass. Das Prog läuft auch schon teilweise ganz gut (noch keine grafische Oberfläche, sondern nur Konsole 🙂 ).

    Hier ein Beispiel, was der schon kann:

    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    ///
    /// FILENAME:   TestClass.h
    /// DESCRIPTION:Test Description
    /// VERSION:    0.01
    ///
    /// COPYRIGHT:  Copyright (C) 2002 by Test Author, Test Company (R)
    ///
    
    ///
    /// HISTORY
    ///
    /// DATE        | AUTHOR        | CHANGE
    /// 08-11-2002    Test Author     File created
    ///
    ///
    
    #ifndef _TESTCLASS_H_
    #define _TESTCLASS_H_
    
    namespace TestNamespace
    {
    
        template<class T, class E>
        class TestClass 
            : public BaseClass,
              private BaseClass2
        {
        public:
    
        protected:
    
        private:
    
        }; // class TestClass
    }; // namespace TestNamespace
    
    #endif
    

    wenn keine Templates angegebn wurden, werden auch keine hinzugefügt. Das gleiche ist auch mit den Basisklassen.

    Das Tool is noch net fertig, hab ja auch nur 2 bis drei stunden dran gesessen. Und es ist noch nicht in C++ programmiert, sondern im ekligen modernen PowerBASIC. Das wird sich bald aber ändern 🙂 Ich wollte mich nämlich erst mit der Programmstruktur/logik auseinandersetzen und nicht mit Stringoperatoren 🙂

    Hoffentlich habt ihr verstanden, was mein kleines Tool macht... 🙂
    Wie findet ihr es? Oder gibts das schon? Und würdet ihr es benutzen, wenn es halbwegs einfach und schnell zu benutzen ist?

    Thx



  • naja viele UML Editoren generieren auch den entsperchenden code, nach den vorgaben des entworfenen UML Diagramms!
    aber prinzipiell eine gute idee.



  • ok, gut 🙂

    mir is da noch was gutes eingefallen. das sollte auch sehr einfach zu implementieren sein.
    jemand hatte hier im forum mal die idee gehabt, c++ kommentare im xml format zu schreiben (wie bei c# es MS will). und der jemand meinte, dass es noch nicht son tool gibt.

    beispiel:

    ///
    /// <class>
    ///  <name>TestClass</name>
    ///  <description>lala. dumdim</description>
    /// </class>
    ///
    class TestClass
    {
    ...
    };
    

    also könnte man in meinen tool etwas integrieren, der aus dieser datei eine komplette xml-datei erzeugt. also eine simple dokumentationstool, wie z.b. doxygen. das ist recht einfach zu implementieren, da ich ja nur alles nach dem dritten slash in die xml-datei schreiben muss. also ganz easy...
    hälst du das auch für eine gute idee?



  • Hi,
    Einen Vorschlag zu deinem Programm:
    Man kann eine Basisklasse angeben und dann in deinem Programm von dieser Klasse erben lassen. Dein Programm erstellt diese Klassen dann und erzeugt automatisch funktionsrümpfe für virtuelle und rein-virtuelle Methoden der Basisklasse.
    Kannst du sowas in der Richtung implementieren? Habe schonmal damit angefangen aber nach ner halben Stunde wieder aufgehört, weil mir irgendwie die Lust vergangen ist **g**



  • kann ich ja mal irgendwann mal machen, wenn mein programm schon halbwegs funktioniert 😉

    fehlen noch ein paar wichtige sachen, wie z.b. eine grafische oberfläche *g
    funktionen, variablen, etc. in der konsole angeben is nich sonderlich schön... und das ganze sollte ja noch nach c++ portiert werden...



  • Hi!

    Schreibe doch ein AddIn für das Visual Studio. Wäre doch dann eine ganz feine Sache.

    Grüße



  • naja, langsam wird das projekt aber etwas zu komplex.. 🙂



  • Also für den MSVC benutze ich so ein Ding schon.
    Ist halt ein wenig schlichter als das, was Du das vorhast, aber mir paßt es bisher recht gut in den Kram.
    Aus ner default.h.cfg

    /*******************************************************************************
    ** Copyright(c) 2002 Volkard Henkel                                           **
    ** http://www.volkard.de                                                      **
    *******************************************************************************/
    
    ////////////////////////////////////////////////////////////////////////////////
    // include guard
    #ifndef CLASS_H__UID
    #define CLASS_H__UID
    #ifdef _MSC_VER
    #pragma once
    #endif
    
    ////////////////////////////////////////////////////////////////////////////////
    // includes
    #include <vhlib/NoCopy.h>
    
    ////////////////////////////////////////////////////////////////////////////////
    // class definition
    class Class:public NoCopy
    {
    private:CURSOR
    public:
        Class()
        {
        }
        ~Class()
        {
        }
    };
    
    ////////////////////////////////////////////////////////////////////////////////
    // include guard
    #endif//CLASS_H__UID
    

    und ner
    default.cpp.cfg

    /*******************************************************************************
    ** Copyright(c) 2002 Volkard Henkel                                           **
    ** http://www.volkard.de                                                      **
    *******************************************************************************/
    
    ////////////////////////////////////////////////////////////////////////////////
    // includes
    #include "pch.h"//for precompiled headers
    #define CLASS_CPP__UID
    #include "Class.h"//to implement here
    
    ////////////////////////////////////////////////////////////////////////////////
    // class implementation
    

    bauts mir nach EIngabe des Klassennamens die entsprechenden Klassenname.h und Klassenname.cpp. Staatt default.*.cfg kann auch ein anderere Name sein, was ich benutze für main.h.cfg (ist leer) und main.cpp.cfg

    /*******************************************************************************
    ** Copyright(c) 2002 Volkard Henkel                                           **
    ** http://www.volkard.de                                                      **
    *******************************************************************************/
    
    ////////////////////////////////////////////////////////////////////////////////
    // includes
    #include "pch.h"//for precompiled headers
    #include <iostream>
    #include <vhlib/Exception.h>
    #include <vhlib/windows.h>
    
    ////////////////////////////////////////////////////////////////////////////////
    // implemetation
    using namespace std;
    
    void test()
    {
        cout<<"start"<<endl;
        CURSOR
        cout<<"end"<<endl;
    }
    
    void wait ()
    {
        cin.clear();
        cin.ignore(cin.rdbuf()->in_avail());
        cin.get();
    }
    int __cdecl main()
    {
        try
        {
            test();
        }
        catch(Exception& e)
        {
            cout<<e<<endl;
        }
        catch(std::exception& e)
        {
            cout<<e.what()<<endl;
        }
        if(IsDebuggerPresent())
        {
            cout<<endl<<"Press any key to continue"<<endl;
            wait();
        }
        return 0;
    }
    

    Da ich meistens mehrere Projekte bearbeite, um eine Anwendung zu erstellen, fragt mich das Tool immer nach Projektname (nur wenn mehr als 1 Projekt offen) und Klassenname.
    ie Suche nach den *.cfg-Dateien geschieht vom entsprechenden Projektverzeichnis aufwärts in Richtung root und der erste match wird verwendet. Dadurch kann man fein Defaulteinstellungen im großen Sourceverzeichnis machen, in den Verzeichnissen für die jeweiligen Arbeitgeber andere Copyrighttexte, standard-includes, coding conventions...
    Von langen Listen der Members und so halte ich wenig, da ich die dann schneller im ganz normalen Editor eingegeben hab, nachdem der Rumpf der Klasse vom Tool erzeugt wurde. Erben hab ich gar nicht vorgesehen, weil ich ja nicht so oft rumerbe. Das ist aber ne nette Idee. Wenn's mich mal nerst, die pur virtuellen Funktionen... Ups, da gibts inhaltliche Probleme. Will ich das denn?



  • hmmmm. auch wieder ne gute idee in den verschiedenen verzeichnissen eine andere default-datei reinzutun.

    aber irgendwie will ich kein vs-addin haben, sondern den den standard-klassending ersezten. also add->add class. da will ich meinen sitzen haben.

    jemand ne idee, wie man das hinkriegen könnte? wenn nicht arbeite ich an meine oberfläche weiter... wäre doch nicht sehr schlimm, wenn das ein externes programm wäre, oder wäre das zu unpraktisch?



  • Kenne kein VS-Admin. Und weiß auch nicht, wie ich sauber das normale File/Add so umbiegen könnte, daß es für meine Zwecke nutzbar ist.
    Aber mir war ausreichend, das Makro mit nem Button zu verbinden und in die Iconleiste vom VS zu stopfen.

    '******************************************************************************'
    '* Copyright(c) 2002 Volkard Henkel                                           *'
    '* http://www.volkard.de                                                      *'
    '******************************************************************************'
    option explicit
    
    function GetProject
     if(Application.Projects.Count=0) then
      MsgBox "No Projekts in Workspace",vbOKOnly+vbInformation
      set GetProject=nothing
      exit function
     end if
     if(Application.Projects.Count=1) then
      set GetProject=Application.ActiveProject
      exit function
     end if
     do
      Dim vProjectName
      vProjectName=InputBox("Name of Projekt","MakeClass",Application.ActiveProject.Name)
      if vProjectName="" then
       set GetProject=nothing
       exit function
      end if
      dim i
      For Each i in Application.Projects
       if(i.Name=vProjectName) then
        set GetProject=i
        exit function
       end if
      next
     loop 'endlos
    end function
    
    function MakeUid
     dim i,vResult
     for i=1 to 8
      vResult=vResult+chr(int(asc("0")+rnd*10))
     next
     MakeUid=vResult
    end function
    
    function FindConfigFile(vFso,vProjectFolder,vName,vExt)
     dim vConfigFolder
     set vConfigFolder=vProjectFolder
     if vFso.FileExists(vConfigFolder.Path&"\"&vName&vExt) then
      MsgBox "File existiert",vbOKOnly+vbInformation
      set FindConfigFile=nothing
      exit function
     end if
     if vFso.FileExists(vConfigFolder.Path&"\"&"default"&vExt&".cfg") then
      set FindConfigFile=vFso.GetFile(vConfigFolder.Path&"\"&"default"&vExt&".cfg")
      exit function
     end if
     set vConfigFolder=vConfigFolder.ParentFolder
     do until vConfigFolder.IsRootFolder
      if vFso.FileExists(vConfigFolder.Path&"\"&vName&vExt&".cfg") then
       set FindConfigFile=vFso.GetFile(vConfigFolder.Path&"\"&vName&vExt&".cfg")
       exit function
      end if
      if vFso.FileExists(vConfigFolder.Path&"\"&"default"&vExt&".cfg") then
       set FindConfigFile=vFso.GetFile(vConfigFolder.Path&"\"&"default"&vExt&".cfg")
       exit function
      end if
      set vConfigFolder=vConfigFolder.ParentFolder
     loop
     if vConfigFolder.IsRootFolder then
      MsgBox "Could not find File",vbOKOnly+vbCritical
      set FindConfigFile=nothing
     end if
    end function
    
    Sub ProcessConfigFile(vStream,vClass,vUid)
     dim vLine
     do while not vStream.AtEndOfStream
      vLine=vStream.ReadLine
      vLine=replace(vLine,"UID",vUid)
      vLine=replace(vLine,"Class",vClass)
      vLine=replace(vLine,"CLASS",UCase(vClass))
      ActiveDocument.Selection=vLine
      ActiveDocument.Selection.NewLine
      ActiveDocument.Selection.StartOfLine
     loop
     ActiveDocument.Selection.FindText "CURSOR",dsMatchFromStart
     ActiveDocument.Selection.Delete
    end sub
    
    Sub MakeFile(vProject,vUid,vClass,vExt)
     dim vFso,vFile,vProjectFolder,vStream
     set vFso=CreateObject("Scripting.FileSystemObject")
     set vProjectFolder=vFso.GetFile(vProject.FullName).ParentFolder
     set vFile=FindConfigFile(vFso,vProjectFolder,vClass,vExt)
     if vFile is nothing then
      exit sub
     end if
     Set vStream=vFile.OpenAsTextStream(1,0)
     if vStream.AtEndOfStream then
      exit sub
     end if
     vProject.AddFile vClass&vExt
     Documents.Add "Text"
     ProcessConfigFile vStream,vClass,vUid
     ActiveDocument.Save vProjectFolder&"\"&vClass&vExt
    end sub
    
    Sub MakeClass()
     dim vProject
     set vProject=GetProject()
     if vProject is nothing then
      exit sub
     end if
     if vProject.Type<>"Build" then
      MsgBox "No Build Project",vbOKOnly+vbCritical
      exit sub
     end if
     dim vClass
     vClass=inputbox("Name of Class","MakeClass")
     if vClass="" then
      exit sub
     end if
     dim vUid
     vUid=MakeUid
     MakeFile vProject,vUid,vClass,".cpp"
     MakeFile vProject,vUid,vClass,".h"
    End Sub
    

Anmelden zum Antworten