Etwas verwirrt mit Headerdateien und weiterreichen von Variablen/Strings



  • Wobei die Programmierung der Metro Aps in c++ des kommenden VS sieht nach CLI aus.^^

    Aber bei dem einen oder anderen Online Auktionshaus bekommt man ein boxes Visual Studio 2003 oder Vs 6 für wirklich kleines Geld, wenn man auf die Neuerungen wie z.B. Ribbons und co verzichten kann und die Finger von den Managed Extension des VS 2002/2003 läst ein funktionierende Lösung.



  • Dean schrieb:

    Wobei die Programmierung der Metro Aps in c++ des kommenden VS sieht nach CLI aus.^^

    Sieht danach aus - ists aber nicht.. das ist C++/CX und basiert auf COM, nicht .NET.



  • Ich fühl mich ehrlich gesagt sehr wenig geholfen. Ich bin Mathematiker/Physiker. Ich programmiere in F95 normalerweise, oder in mathematica. Ich will jetzt nicht hergehen und mir irgendwas kaufen (das könnte die UNI dann erst wieder nicht verwenden). Ich würde gerne einfach wissen, wie ich mein Problem lösen kann.



  • Ok, ich versuche mal zu helfen, ich werde aber das Gefühl nicht los, das es sehr schwierig wird. 😞

    calc.cpp und die main.cpp included

    Source (=cpp) Dateien dürfen nicht inkludiert werden. Nur header Dateien.

    Aber zeige doch mal noch main.cpp und Form1.h.



  • Zum problem:
    Du musst in der Form1.h einfach die "calc.h" includen. Dann kannst Du in Deinen Event-Handlern auf die Dinge von "calc.h" zugreifen und somit auch Methoden in "calc.cpp" aufrufen, wenn Du sie in "calc.h" deklariert hast.



  • Das habe ich schon gemacht, ich glaube aber ich stolpere über den Syntax. Das std::string in der clac.h war offensichtlich falsch, für mein Vorhaben eine Funktion in die calc.cpp zu tun, die dann einen String zurückliefert.

    Wo kann ich das gut nachlesen, wie das mit der Deklaration am besten funktioniert? Ich habe schon einige Tutorials versucht, aber in keinem was dazu gefunden. Gibts wo einen Beispielcode zufälligerweise?



  • Du mußt in der "calc.h" natürlich auch den passenden Header einbinden, damit er std:string kennt:

    #ifndef CALC_H
    #define CALC_H
    
    #include <string>
    
    // ...
    
    extern std::string name;
    
    #endif
    

    Und so wie bei den anderen Variablen mußt du dann in der "calc.cpp" eine Definition vornehmen:

    std::string name;
    

    Globale Variablen sind aber ein sehr unsauberer Programmierstil.

    Und so wie einige schon geschrieben haben: C bzw. C++ und CLI zu mischen ist keine gute Idee (vorallendingen da du anscheindend in beiden nicht firm bist).



  • Du mischst da wie gesagt 2 verschiedene Dinge.

    std::string ist c++, system::String ist net Framework

    c++ verwendet einen nativ Heap, das net Framewortk mit c++/cli einen Heap mit Garbage Collection. Windows Forms ist Net Framework. Wenn Du mit Windows Forms und C++/CLI arbeiten möchtest müssen system:: Datentypen verwendet werden nicht std::.

    http://www.functionx.com/cppcli/index.htm

    Wenn Du mit c++ arbeiten möchtest kannst Du mit std:: Datentypen arbeiten ( was nicht so verkehrt ist ), dann machen allerdings Windows Forms keinen Sinn bzw es ist mehr als aufwendig. C++/cli ist genau die Schnittstelle zwischen den beiden "Welten".

    Als GUI Toolkit( Grafische Oberflächen) bietet sich da wie gesagt die MFC an, das Visual Studio 2010 Pro gibt es als 180 Tage Testversion kostenfrei zum Download. Oder kostenfrei alternativen wie z.B. Qt, WXWidgets oder andere.

    Visual C++ 6 oder 2002/2003 Standart gibt es wie gesagt boxed für richtig kleines Geld bei z.B. Ebay für 20,00 oder 50,00 da ist die MFC bei.



  • conqueror24 schrieb:

    Das habe ich schon gemacht, ich glaube aber ich stolpere über den Syntax. Das std::string in der clac.h war offensichtlich falsch, für mein Vorhaben eine Funktion in die calc.cpp zu tun, die dann einen String zurückliefert.

    Wo kann ich das gut nachlesen, wie das mit der Deklaration am besten funktioniert? Ich habe schon einige Tutorials versucht, aber in keinem was dazu gefunden. Gibts wo einen Beispielcode zufälligerweise?

    Zeige doch einfach mal dein Form1.h.

    Ich denke, es ist nicht verkehrt std::string in calc.h zu verwenden - das Problem ist, dass die RichTextBox einen System::String verwendet (noch dazu ein Ref Handle). Das heisst Du musst zwischen diesem beiden Typen convertieren.

    http://www.c-plusplus.net/forum/158664

    EDIT:
    Hier noch ein Bsp. inkl. verwendung von globalen Variabeln - sollte man nicht tun kommt aber deinem Problem näher.

    Form1.h

    #pragma once
    
    #include <msclr\marshal_cppstd.h>
    using namespace msclr::interop;
    
    #include "Calc.h"
    
    namespace Test {
    
    	using namespace System;
    	using namespace System::ComponentModel;
    	using namespace System::Collections;
    	using namespace System::Windows::Forms;
    	using namespace System::Data;
    	using namespace System::Drawing;
    
    	/// <summary>
    	/// Summary for Form1
    	/// </summary>
    	public ref class Form1 : public System::Windows::Forms::Form
    	{
                    // ... nicht relevante Dinge rausgenommen...
    
        private: System::Void calcButton_Click(System::Object^  sender, System::EventArgs^  e) {
    
                     String^ s = richTextBox->Text;
    
                     calc::text = marshal_as<std::string>(s);
    
                     calc::f();
    
                     richTextBox->Text = gcnew String(calc::text.c_str());
                 }
        };
    }
    

    Calc.h

    #pragma once
    
    #include <string>
    
    namespace calc
    {
        extern std::string text;
    
        void f();
    }
    

    Calc.cpp

    #include "stdafx.h"
    #include "Calc.h"
    #include <algorithm>
    
    namespace calc
    {
        std::string text;
    
        void f()
        {
            std::reverse(begin(text), end(text));
        }
    }
    


  • Danke erstmal für deine Mühe, hier ausschnittweise meine form1.h (ich poste mal nicht alles, weil ich vermute dass das nur Leseaufwand aber keine Information mehr bringt:

    form1.h:

    private: System::Void mach_was_Click(System::Object^  sender, System::EventArgs^  e) {
    
    			String^ Inhalt_richTextBox1 = richTextBox1->Text;
    			MessageBox::Show(aendern(Inhalt_richTextBox1));
    
    			 }
    

    calc.h:

    #pragma once
    
    #ifndef CALC_H
    #define CALC_H
    
    #include <string>
    
    namespace diese_und_jene_Variable	{
    
    	extern int block_whs;
    	extern int block_abstand;
    	extern int zeichen_anz;
    	extern std::string Inhalt_richTextBox1;
    }
    
    #endif
    

    calc.cpp:

    #include "stdafx.h"
    #include <sstream>
    #include <string>
    #include <cmath>
    #include "calc.h"
    
    using namespace std;
    
    namespace diese_und_jene_Variable	{
    
    	// Anfangswerte festsetzen
    
    	int block_whs = 0;
    	int block_abstand = 0;
    	int zeichen_anz = 0;
    	std::string Inhalt_richTextBox1;
    }
    
    std::string aendern(std::string Inhalt_richTextBox1)	{
    	using namespace diese_und_jene_Variable;
    	Inhalt_richTextBox1 = "HALLO";
    return Inhalt_richTextBox1;}
    

    Was ich an deinem Code nicht ganz verstehe, ist warum du die void f(); im namespace hast. Sollte ich das auch machen? Ich habe das bisher immer so gemacht, wie du es aus meinem Code ablesen kannst. Oder ist das unfein?

    Ich habe nun das Problem, dass er meint

    error C3861: "aendern": Bezeichner wurde nicht gefunden.

    .

    Kannst du mir diese Schreibweise erläutern: [quote]namespacename::text = std::string(stringname);



    Die globale Variable Inhalt_richTextBox1 im Namespace diese_und_jene_Variable brauchst Du nicht, wenn Du den Text sowiso als Argument der Funktion aendern(..) übergibtst. (Was auch gut so ist.)

    error C3861: "aendern": Bezeichner wurde nicht gefunden.

    Die Fehlermeldung deutet daraufhin, dass vermutlich calc.h in form1.h nicht inkludiert ist. Also: calc.h in form1.h inkludieren. Wenn das schon der Fall ist, ist die Funktion in calc.h nicht deklariert - das geht so:

    calc.h

    #pragma once
    
    namespace diese_und_jene_Variable
    {
       // ...
    }
    std::string aendern(std::string Inhalt_richTextBox1);
    

    Schreibe die Zwischenresultate ruhig in Variablen - so siehst Du welche Typen mit welchen interagieren müssen. Das würde z.B. bei MessageBox::Show(aendern(...)); helfen, denn aendern(..) gibt ein std::string zurück und MessageBox::Show(..) kann mit dem nicht umgehen.

    Was ich an deinem Code nicht ganz verstehe, ist warum du die void f(); im namespace hast. Sollte ich das auch machen? Ich habe das bisher immer so gemacht, wie du es aus meinem Code ablesen kannst. Oder ist das unfein?

    Namespaces sind da um Namenskonflikte zu vermeiden... das sasgt irgendwie schon alles, oder? Unfein oder nicht...? Ich finde Namespaces kann zur logischen Unterteilung benutzt werden und das ist fein. 🕶

    Kannst du mir diese Schreibweise erläutern:

    namespacename::text = std::string(stringname);

    Ich nehme an du sprichst auf folgende Code Zeilen an, siehe anbei meine Kommentare im Code:

    // Text der richTextBox in eine Variable vom Typ String^ (Ref. Handle auf String Objekt) speichern.
    String^ s = richTextBox->Text;
    
    // Inhalt von s (Typ: System::String^) in calc::text (Typ: std::string) konvertieren.
    calc::text = marshal_as<std::string>(s);
    
    // Geänderter std::string mit Hilfe von c_str() wieder in ein System::String umwandeln und bei der richTextBox den Text setzten.
    richTextBox->Text = gcnew String(calc::text.c_str());
    

    Edit:
    Das ist eben das Problem an der Sache. Du musst beide Welten (.NET und native C++) kennen und zwar gut. An den Grenzen musst Du jeweils von der einen Welt in die andere konvertieren. Du musst andauernd Probleme lösen, die Du dir durch den Windows Forms / C++/CLI Ansatz einhandeltst und sonst gar nicht hättest.



  • included hatte ich das schon, deswegen habe ich mich gewundert, wo mein Fehler her kam. Den Rest deiner Antwort muss ich jetzt mal in Ruhe durchgehen 🙂



  • Ich glaube ich komme der Sache näher 🙂

    - ich habe die math.h included in form1.h (hatte ich vorher schon) und diese beiden Zeilen habe ich ebenfalls übernommen:

    #include <msclr\marshal_cppstd.h>
    using namespace msclr::interop;

    - was genau macht marshal_as - ich habe ein wenig nachgegoogelt und gefunden, dass es für native/managed Variablen und dem herumwechseln damit zu tun hat - wann ist mein "uebergabe_string_1" managed, wann ist er native?

    - kann ich generell wenn ich eine funktion habe immer Variablen aus verschiedenen Namespaces verwenden, indem ich

    namespacename::variablenname

    verwende, anstelle von

    using namespacename;

    und dann gilt es für die ganze Funktion? Oder genauer gefragt, unterscheidet der Compiler (korrekt) zwischen

    namespacename1::Variable1

    und

    namepspacename2::Variable1

    ?

    Jetzt bekomme ich beim Ausführen folgenden Fehler:

    1> calc.cpp
    1>v3.obj : error LNK2028: Nicht aufgelöstes Token (0A000021) ""void __clrcall diese_und_jene_Variable::aendern(void)" (?aendern@diese_und_jene_Variable@@$$FYMXXZ)", auf das in Funktion ""private: void __clrcall v3::Form1::mach_was_Click(class System::Object ^,class System::EventArgs ^)" (?mach_was_Click@Form1@v3@@$$FAAAMXPAAMXPAAVObject@System@@PAAVEventArgs@4@@Z)" verwiesen wird. 1>v3.obj : error LNK2019: Verweis auf nicht aufgelöstes externes Symbol ""void \_\_clrcall diese\_und\_jene\_Variable::aendern(void)" (?aendern@diese\_und\_jene\_Variable@@FYMXXZ)"inFunktion""private:void__clrcallv3::Form1::mach_was_Click(classSystem::Object,classSystem::EventArgs)"(?mach_was_Click@Form1@v3@@FYMXXZ)" in Funktion ""private: void \_\_clrcall v3::Form1::mach\_was\_Click(class System::Object ^,class System::EventArgs ^)" (?mach\_was\_Click@Form1@v3@@FAFAAAMXPAAVObject@System@@PAAVObject@System@@PAAVEventArgs@4@@Z)".
    1>C:\Users...exe : fatal error LNK1120: 2 nicht aufgelöste externe Verweise.

    Hier meine Dateien:

    calc.cpp

    #include "stdafx.h"
    #include <sstream>
    #include <string>
    #include <cmath>
    #include "calc.h"
    
    using namespace std;
    
    namespace diese_und_jene_Variable	{
    
    	// Anfangswerte festsetzen
    
    	int block_whs = 0;
    	int block_abstand = 0;
    	int zeichen_anz = 0;
    	std::string uebergabe_string_1;
    }
    
    void aendern()	{
    	diese_und_jene_Variable::uebergabe_string_1 = "Test erfolgreich!"; 
    
    };
    

    calc.h:

    #pragma once
    
    #ifndef CALC_H
    #define CALC_H
    
    #include <string>
    
    namespace diese_und_jene_Variable	{
    
    	extern int block_whs;
    	extern int block_abstand;
    	extern int zeichen_anz;
    	extern std::string uebergabe_string_1;
    
    void aendern(); 
    }
    
    #endif
    

    form1.h (auszugsweise):

    #pragma once
    #include "calc.h"
    #include <msclr\marshal_cppstd.h>
    using namespace msclr::interop; 
    namespace v3 {
    
    	using namespace System;
    	using namespace System::IO;
    	using namespace System::ComponentModel;
    	using namespace System::Collections;
    	using namespace System::Windows::Forms;
    	using namespace System::Data;
    	using namespace System::Drawing;
    
    	/// <summary>
    	/// Zusammenfassung für Form1
    	/// </summary>
    .
    .
    .
    .
    
    private: System::Void richTextBox1_TextChanged_1(System::Object^  sender, System::EventArgs^  e) {
    		 }
    private: System::Void mach_was_Click(System::Object^  sender, System::EventArgs^  e) {
    
    			//erstellt einen String vom Typ system::String^ 
    			String^ Inhalt_richTextBox1 = richTextBox1->Text;
    
    			//Konvertiert den String in das Format std::string
    			diese_und_jene_Variable::uebergabe_string_1 = marshal_as<std::string>(Inhalt_richTextBox1); 
    
    			//Funktionsaufruf
    			diese_und_jene_Variable::aendern();
    
    			//Konvertierung von std::string zurück in System::string und Ausgabe in der richTextBox1
    			richTextBox1->Text = gcnew String(diese_und_jene_Variable::uebergabe_string_1.c_str()); 
    
    			 }
    private: System::Void Form1_Load(System::Object^  sender, System::EventArgs^  e) {
    		 }
    };
    }
    


  • Ich fürchte ich habe deinen Punkt 2 nur bruchstückhaft befolgt *ascheaufmeinhaupt*.

    Wenn ich nun also der Funktion aendern den String aus richTextBox1 übergeben will, muss ich sie mit

    std::String Funktionsname(std::String Stringname1, std::String Stringname2 ...);
    

    aufrufen. Dann muss ich aber in der calc.h sie erst nach dem namespace definieren, in den Namespace müssen Stringname1 und Stringname2 nicht hinein, sehe ich das richtig?

    Noch eine weitere Frage habe ich: Kann man generell sagen, dass alles was ich zum rechnen verwende immer std:: sein muss und alles was aus einer Form kommt immer System:: ist?



  • Ich glaube ich komme der Sache näher

    Da bin ich mir nicht so sicher... 🕶

    Es soll gesagt sein: Benutze cmath anstatt math.h.

    - was genau macht marshal_as - ich habe ein wenig nachgegoogelt und gefunden, dass es für native/managed Variablen und dem herumwechseln damit zu tun hat - wann ist mein "uebergabe_string_1" managed, wann ist er native?

    Genau, es konvertiert zwischen managed (C++/CLI) und native (C++). System::String ist managed, std::string ist native.

    - kann ich generell wenn ich eine funktion habe immer Variablen aus verschiedenen Namespaces verwenden, indem ich...

    Ja. Das gilt nicht nur für Variablen, sondern für Klasse, Structs, Funktionen...

    und dann gilt es für die ganze Funktion? Oder genauer gefragt, unterscheidet der Compiler (korrekt) zwischen...

    Ja. Das sind zwei unterschiedliche Variablen.

    Jetzt bekomme ich beim Ausführen folgenden Fehler: ...

    Nicht beim Ausführen, sondern beim Linken. Das kommt daher, dass Du die Funktion aendern(..) im Namespace diese_und_jene_Variable deklariert, aber im globablen NS definiert hast. Der Linker findet die Definition der Funktion nicht!

    Noch eine weitere Frage habe ich: Kann man generell sagen, dass alles was ich zum rechnen verwende immer std:: sein muss und alles was aus einer Form kommt immer System:: ist?

    Kann man sagen wenn man will. Könnte man so als Daumenregel halten.

    Hier noch eine korrigierte Fassung deines Codes.

    In Form1.h

    private: System::Void mach_was_Click(System::Object^  sender, System::EventArgs^  e) {
    
            std::string text = marshal_as<std::string>(richTextBox1->Text); 
            std::string resultat = diese_und_jene_Variable::aendern(text);
            richTextBox1->Text = gcnew String(resultat.c_str());
        }
    

    calc.h

    #pragma once
    
    #include <string>
    
    namespace diese_und_jene_Variable
    {
        std::string aendern(const std::string& text); 
    }
    

    calc.cpp

    #include "stdafx.h"
    #include "calc.h"
    
    namespace diese_und_jene_Variable
    {
        std::string aendern(const std::string& text)
        {
            return "Test erfolgreich: " + text;
        };
    }
    

    Irgendwie ist das ziemlich hoffnungslos - es fehlen die Grundlagen, aber ganz krass.

    Edit:
    a.) Ich hoffe Du hast bemerkt, dass keine globale Variable (std::string Inhalt_richTextBox1;) nötig ist.
    b.) Das Argument bei der Funktion aendern(..) als const & zu Übergeben erspart eine Kopie (nur als Hinweis).



  • Ja, das bemerke ich auch gerade. Ich dachte mir circa vor ein paar Tagen noch sowas wie "Wie schwer kann es sein, deine ganzen Fortran Codes in Visual umzuschreiben..." 🙂

    Werd mich weiter durchackern, danke für deine Hilfe soweit!



  • Noch eine Frage: Warum cmath statt math.h?



  • Edith: ich hatte eh cmath - oder meintest du es andersrum? Lieber math.h?



  • conqueror24 schrieb:

    Edith: ich hatte eh cmath - oder meintest du es andersrum? Lieber math.h?

    Lieber cmath weil Standard.



  • Kann ich das getrost vergessen (Kein Fehler, ein Warning)?

    Warnung	1	warning C4101: 'ex': Unreferenzierte lokale Variable	c:\users\ra\desktop\vigenere\vigenere\v3\Form1.h	185
    

    Das kommt von der Zeile:

    catch(Exception^ ex)	{MessageBox::Show("Datei unlesbar"); }
    

    Oder gibt es einen guten Grund, warum ich die Warnung nicht einfach übergehen sollte 🙂


Anmelden zum Antworten