grundlegendes Verständnisproblem: namespace-Verwendung mit 2 Dateien ohne Header



  • sorry, das war ein abtippfehler (der 4. arrrg), das ist es nicht.



  • Hi,

    also ich würde mal die "precompiled Header"-Option rausnehmen (inkl. der "stdafx.h").
    Das funktioniert nämlich manchmal nicht so gut und führt bisweilen zu solchen Phänomenen...

    Gruß,

    Simon2.



  • Simon2 schrieb:

    also ich würde mal die "precompiled Header"-Option rausnehmen (inkl. der "stdafx.h").
    Das funktioniert nämlich manchmal nicht so gut und führt bisweilen zu solchen Phänomenen...

    Hallo, bringt leider nichts. Trotzdem Fehler.

    Wenn ich die Direktive

    #include "ShopAuch.cpp"
    

    rausnehme, kennt er den Namensraum nicht (using ...), und wenn ich sie reinehme behauptet der Compiler

    error LNK2005: "int __cdecl myshopauch::countArticles(void)" (?countArticles@myshopauch@@YAHXZ) already defined in Run.obj

    harrr 😡
    Ich könnte ja einfach einen Header benutzen, aber irg. macht mich das fuchsig



  • PeterFragt schrieb:

    und wenn ich sie reinehme behauptet der Compiler

    error LNK2005: "int __cdecl myshopauch::countArticles(void)" (?countArticles@myshopauch@@YAHXZ) already defined in Run.obj

    Das ist nicht der Compiler, sondern der Linker.

    Du solltest Funktionsdefinitionen nicht in Headerdateien schreiben (Ausnahme Templates oder inline -Funktionen). Implementiere die Funktionen in .cpp-Dateien und schreibe nur die Deklaration in den Header.



  • Zu deiner Datei 2: Run.cpp

    // ...
    namespace myshopauch{ 
      int countArticles(); // Deklaration gehört auch in den Namensraum
    }
    // ...
    

    Ganz davon abgesehen das man immer mit Headern arbeiten sollte...



  • Die Deklaration der benutzten Objekte/Typen muß ja zur Compilezeit bekannt sein. In Deinem ursprünglich geposteten Beispiel ist aber in run.cpp keine Deklaration für countArticles vorhanden.



  • Nachtrag:

    Das ist, als wenn ich

    using namespace std;

    benutzen würde, und dann mit zB string arbeiten wollte, ohne daß

    #include <string>

    vorhanden ist.



  • mh

    Du solltest Funktionsdefinitionen nicht in Headerdateien schreiben

    Wie kommst du darauf, dass ich das gemacht habe? Ich habe keine Header-Files mehr im Projekt.

    Implementiere die Funktionen in .cpp-Dateien und schreibe nur die Deklaration in den Header

    Damit ging es ja, ich will nur wissen, wieso das nicht ohne klappt.

    Ganz davon abgesehen das man immer mit Headern arbeiten sollte...

    Jau, ich war nur neugierig, warum/wie das ohne geht. Anscheinend nicht zu unrecht, weil es ja nicht problemlos klappte

    namespace myshopauch{
      int countArticles(); // Deklaration gehört auch in den Namensraum
    }
    

    Mh, die Deklaration (und Definition) findet doch in der ShopAuch.cpp statt?



  • #include <stdio.h>
    #include <string>
    #include <iostream>
    #include "ShopAuch.cpp"
    using namespace myshopauch;
    
    int countArticles();
    
    int main()
    {
    	int zahl = -1;
    	zahl = countArticles();
    	std::cout << zahl << std::endl;
    
    	// Pro Forma
    	std::cout << "Och, schon zuende?";
    	getchar();
    
    	return 0;
    }
    

    Führt dazu, dass der Compiler (ja, wirklich der Compiler) meckert:

    1>f:\visual studio 2008\projects\pointertest\pointertest\namespacetest\namespacetest.cpp(18) : error C2668: 'countArticles' : ambiguous call to overloaded function
    1>        f:\visual studio 2008\projects\pointertest\pointertest\namespacetest\namespacetest.cpp(11): could be 'int countArticles(void)'
    1>        f:\visual studio 2008\projects\pointertest\pointertest\namespacetest\shopauch.cpp(16): or       'int myshopauch::countArticles(void)'
    1>        while trying to match the argument list '(void)'
    


  • PeterFragt schrieb:

    #include "ShopAuch.cpp"
    

    Wo lernt man denn so was?

    Grundsätzliches für Ungeübte:
    1. Deklaration gehört ins .h,
    2. Definition ins .cpp.
    3. das .h File mit #include guards ausstatten und
    4. nur .h Files inkludieren



  • PeterFragt schrieb:

    Wie kommst du darauf, dass ich das gemacht habe? Ich habe keine Header-Files mehr im Projekt.

    Weil man normalerweise Headerdateien inkludiert und das ein sehr häufiger Fehler ist. Dadurch, dass du .cpp-Dateien inkludiert hast, hast du den gleichen Effekt erzielt. Diese inkludiert man aber nicht!

    Wieso willst du auf Header verzichten, aber stattdessen .cpp-Dateien als Header missbrauchen?



  • PeterFragt schrieb:

    Definiere ich mir jetzt aber einen Header für die Datei ShopAuch.cpp mit namespace (und lösche die Vorwärtsdeklaration aus der Run.cpp) kompiliert das wunderbar.

    Das ist schon der richtige Weg.



  • Mh, irg. scheine ich mein Problem nicht gut rüberzubringen.

    also ich hab einfach nur mit Namespaces (und 2 Dateien) rumgespielt und das klappte nur mit Header aber nicht ohne.
    Da ich neugierig bin, hab ich den namespace weggelassen (ohne Header-Datei) und es klappte. Also kam ich auf den Gedanken, dass ich für einen Namespace immer einen Header benötige, und wenn nein, wieso ich das im Code nicht hinbekomme.

    Das mit dem cpp Dateien inkludieren war nur ein verzweifelter Versuch, weil sonst der (ich glaub) Compiler meldet, dass er den Namensraum nicht findet.



  • poste halt mal ein minimalbsp - und zwar nicht mit irgendwas drin, wie "alles andere ging nicht und dann hab ich halt einfach irgendwas hingeschrieben"...

    dann können wir dir deinen fehler wahrscheinlich relativ schnell zeigen

    bb



  • PeterFragt schrieb:

    Mh, irg. scheine ich mein Problem nicht gut rüberzubringen.

    also ich hab einfach nur mit Namespaces (und 2 Dateien) rumgespielt und das klappte nur mit Header aber nicht ohne.
    Da ich neugierig bin, hab ich den namespace weggelassen (ohne Header-Datei) und es klappte. Also kam ich auf den Gedanken, dass ich für einen Namespace immer einen Header benötige, und wenn nein, wieso ich das im Code nicht hinbekomme.

    In der zu kompilierenden Datei brauchst Du Deklarationen für die Typen/Funktionen, die Du benutzen möchtest. In Deinem Beispiel ohne Namensraum hast Du eine entsprechende Deklaration in der run.cpp gehabt.
    In Deinem Beispiel mit Namensraum ist keine Deklaration für die Funktion countArticles in der run.cpp. Das kann nicht kompiliert werden.



  • Mal zwischendrin ein Danke an alle für die Geduld 😃

    Minibeispiel, das nicht kompiliert:

    #include <stdio.h>
    #include <string>
    #include <iostream>
    using namespace myshopauch; // einziger Unterschied mit Namespace, der nicht bekannt ist, wenn ich keinen Header verwende in der ShopAuch.cpp
    
    int countArticles(); // Vorwärtdeklaration
    
    int main()
    {
    	int zahl = -1;
    	zahl = countArticles();
    	return 0;
    }
    
    #include <stdio.h>
    #include <string>
    
    namespace myshopauch{ // Das hier weglassen und die using Anweisung und es kompiliert
    	int countArticles()
    	{
    		return 3;
    	}
    }
    

    Fehlermeldung:

    1>f:\visual studio 2008\projects\pointertest\pointertest\namespacetest\namespacetest.cpp(7) : error C2871: 'myshopauch' : a namespace with this name does not exist
    


  • wenn du
    int countArticles(); // Vorwärtdeklaration
    schreibst, ist klar, dass es nicht geht...

    1. nimmt man dafür header und
    2.:

    namespace mybla
    {
      int countArticles();
    }
    

    bb

    PS:
    #include <stdio.h>
    ist kein gültiges C++
    der header (den du hier gar nicht brauchst) heißt <cstdio>

    und

    int main()
    {
    /*...*/
      return 0; //brauchst du nicht
    }
    

    edit - also so:

    /*main.cpp*/
    
    #include "foo.h"
    int main()
    {
      my::foo();
    }
    
    /*foo.h*/
    
    namespace my
    {
      void foo();
    }
    
    /*foo.cpp*/
    
    #include "foo.h"
    void my::foo()
    {
      /*...*/
    }
    

    alternative für die foo.cpp:

    /*foo.cpp*/
    
    #include "foo.h"
    namespace my{
    
    void foo()
    {
      /*...*/
    }
    
    } //namespace my
    


  • Ich verstehe nicht, wieso du auf Header verzichten willst, es geht aber natürlich auch ohne, mit extern:

    namespace XY {
    
        int test() {
            return 4;
        }
    
    }
    
    #include <iostream>
    
    using namespace std;
    
    namespace XY {
        extern int test();
    }
    
    int main() {
        cout << XY::test() << endl;
        cin.get();
        return 0;
    }
    

    Du musst den Namespace in beiden Dateien definieren, die Funktion muss mit extern deklariert werden, dann weiß der Compiler, dass sich der Linker darum kümmern muss, die Funktion zu finden.



  • Ad aCTa schrieb:

    Ich verstehe nicht, wieso du auf Header verzichten willst, es geht aber natürlich auch ohne, mit extern:
    [...]

    [...]
    namespace XY {
        extern int test();
    }
    [...]
    

    Das extern ist hier überflüssig. eine Funktionsdeklaration in einem nicht-anonymen Namensraum führt automatisch schon einen Namen (hier "test") mit externer Bindung (external linkage) ein.

    Peter, Du vermischst hier verschiedene Konzepte, die nicht viel miteinander zu tun haben. Namensräume sind total unabhängig davon, wo und wie Quellcode gespeichert wird (im Gegensatz zu den Java Packages zum Beispiel). Das Konzept einer Übersetzungeinheit und was #include eigentlich macht, solltest Du Dir auch nochmal angucken. "Header-Dateien" sind auch nichts Besonderes. Den Compiler interessiert es nicht die Bohne, woher der Quellcode kommt. Das mit den Header-Dateien ist nur eine Konvention, die sich entwickelt hat -- eine gute Konvention. Ein anderes wichtiges Konzept ist die Bindung (linkage).

    In jedem guten C++ Buch sollte das alles geklärt werden. Man kann sich echt viel Zeit und Ärger sparen, wenn man das einfach mal nachließt. Ich weiß ja nicht, wie's Euch geht/ging, aber ich fand das höchst unbefriedigend, nicht den Durchblick bzgl Header, Namensräume, Bindung, "One-Definition-Rule", ... zu haben.

    Gruß,
    SP



  • Ad aCTa schrieb:

    Ich verstehe nicht, wieso du auf Header verzichten willst, es geht aber natürlich auch ohne, mit extern:

    namespace XY {
    
        int test() {
            return 4;
        }
    
    }
    
    #include <iostream>
    
    using namespace std;
    
    namespace XY {
        extern int test();
    }
    
    int main() {
        cout << XY::test() << endl;
        cin.get();
        return 0;
    }
    

    Du musst den Namespace in beiden Dateien definieren, die Funktion muss mit extern deklariert werden, dann weiß der Compiler, dass sich der Linker darum kümmern muss, die Funktion zu finden.

    Danke, jetzt klappt es!

    Nochmal, bevor einige hier nicht schlafen können 🙂
    Ich weiß, dass ich eine Header-Datei benutzen sollte, aber als es klappte war da diese Neugier, ob ich das auch ohne kann, so als Beweis. Und wie ihr seht konnte ich das nicht, also waren da wohl noch Lücken!

    Gerade für OOP sind explizite Schnittstellen ja durchaus eine sinnvolle Sache 👍

    Danke allen!


Anmelden zum Antworten