Klassen über Header verbunden funktionieren nicht wie sie sollen...



  • Hi,

    ich wollte mich grade einw enig in Headerdateien und so einarbeiten und habe dazu eine Klasse "Testprogram" mit Header und .cc Teil programmiert. Ein Objekt erstelle ich dann in der Datei start.cc, hier sind die Dateien:

    Testprogramm.hh:

    #include <iostream>
    #include <cstdio>
    
    using namespace std;
    
    class Testprogram
    {
    
    public:
        Testprogram();
        void ausgabe(); 
    
    };
    

    Testprogramm.cc:

    #include <iostream>
    #include <cstdio>
    
    #include "Testprogram.hh"
    
    using namespace std;
    
    void Testprogram::Testprogram()
    {
      cout<<"ich wurde erstellt!"<<endl;
    }
    
    void HotEnergy::ausgabe()
    {
      cout<<"Und die Ausgabe funktioniert auch!"<<endl;
    }
    

    start.cc:

    #include "Testprogram.hh"
    
    using namespace std;
    
    int main()
    {
      Testprogram objekt1;
      objekt1.ausgabe();
    }
    

    aber wenn ich kompelieren möchte bekomme ich immer den Fehler:

    undefenied reference to...

    wo ist mein Denkfehler?

    danke schon mal 🙂

    Liebe Grüße
    Laura



  • Schau dir mal deine Ausgabefunktion an. Deine Klasse hats Testprogramm und dort steht

    void HotEnergy::ausgabe(){ //.. }
    
    // muestte aber:
    void Testprogramm::ausgeben(){ //.. }
    // geschrieben werden
    

    Die Klasse HotEnergy kennt dein Programm nicht.



  • Prometheus87 schrieb:

    Testprogramm.hh:
    [cpp]
    #include <iostream>
    #include <cstdio>

    using namespace std;

    Nein und nein. Include-Guards fehlen und ein using namespace std; hat in einem Header auf globaler Ebene nichts zu suchen. Du musst Dir darüber im Klaren sein, dass ein #include (logisch gesehen) nur vom Preprocessor ausgewertet wird, welcher eine reine Textersetzung macht. Alle anderen Regeln ergeben sich aus der ODR (one definition rule, bitte im Buch nachschlagen). Include-Guards haben sich als "best practice" herausgebildet.

    Prometheus87 schrieb:

    [...]
    aber wenn ich kompelieren möchte bekomme ich immer den Fehler:

    undefenied reference to...

    wo ist mein Denkfehler?

    danke schon mal 🙂

    Strenggenommen ist das kein Kompilierfehler sondern ein Linkerfehler. Typischerweise sind das zwei Schritte, die man getrennt durchführen kann.
    1. Kompilieren, c/cpp/h/hpp --> o/obj
    2. Verbinden, o/obj --> exe

    Das Zwischenergebnis sind sogenannte Objektdateien. In Deinem Fall hat sich der Linker beschwert, dass er eine Definition nicht gefunden hat. Wahrscheinlich hast Du versucht, aus indirekt nur einer Objekt-Datei eine ausführbare Datei zu erzeugen, wobei in einer anderen Objekt-Datei eine noch benötigte Funktionsdefinition enthalten ist, die dem Linker jetzt hier fehlt.

    Stichwort dazu: Getrennte Übersetzung

    Wenn Du Dich vorher mit beispielsweise Java auseinander gesetzt hast und auf G++ umsteigst, dann ist das keine Überraschung. Der "Standard-" Java-Compiler kompiliert automatisch alles benötigte. Beim G++ musst du alle Quelldateien (nur *.cpp, keine Header!) mit angeben. Also:

    > g++ -c tu1.cpp
    > g++ -c tu2.cpp
    > g++ -o fertig tu1.o tu2.o
    

    oder in einem Schritt:

    > g++ -o fertig tu1.cpp tu2.cpp
    

    wobei das "-c" für das Erzeugen der Objektdateien ist und über "-o" der Dateiname für das "Binary" angegeben werden kann.



  • argh, vesur, sorry!

    hab das aus meinem Originalversuch (das Programm heißt HotEnergy...), rauskopiert weils nicht funktioniert hat, und wollte es hier mit "normalen" Namen reinsetzen, das hab ich vergsessen zu verändern, hat aber mit meinem Problem nix zu tun

    @krümelkacker:

    thx, und richtig geraten, komme von Java, und da gabs kein Header-Zeugs...;-)

    aber funktioniert leider immer noch nicht... momentane Dateien:

    Testprogram.cc:

    #include <iostream>
    #include <cstdio>
    
    #include "Testprogram.hh"
    
    using namespace std;
    
    void Testprogram::Testprogram()
    {
      cout<<"ich wurde erstellt!"<<endl;
    }
    
    void Testprogram::ausgabe()
    {
      cout<<"Und die Ausgabe funktioniert auch!"<<endl;
    }
    

    Testprogram.hh:

    #include <iostream>
    #include <cstdio>
    
    class Testprogram
    {
    
    public:
        Testprogram();
        void ausgabe(); 
    
    };
    

    start.cc:

    #include "Testprogram.hh"
    
    using namespace std;
    
    int main()
    {
      Testprogram objekt1;
      objekt1.ausgabe();
    }
    

    Er gibt einen Fehler in Testprogram.cc in line 8 aus:

    return type specification for constructor invalid

    kann mir da noch jemand helfen? danke 🙂



  • ah habs, Konstruktor ohne Rückgabetyp, dann funktionierts! 🙂

    danke nochmal an alle!

    Ich glaube mich übrigens zu erinnern, mal ein scons benutzt zu haben um was zu compelieren... muss man da dann nicht jede Datei einzeln erwähnen?



  • Include-Guards fehlen noch:

    Testprogram.hh

    #ifndef TESTPROGRAM_HH_INCLUDED
    #define TESTPROGRAM_HH_INCLUDED
    
    class TestProgramm
    {
    public:
      TestProgramm();
      void ausgabe();
    };
    
    #endif
    

    Du brauchst hier auch kein #include<iostream> im Header. Benutzt Du ja gar nicht.

    Ein gutes Build-System nimmt Dir da vieles ab, ja. Ich verwende da meist das eingebaute der IDE oder auch mal ein von Hand geschriebenes Makefile unter Linux. Für ein Projekt habe ich auch cmake ausprobiert. So richtig klar komme ich damit aber nicht und ich finde es nervig, ständig in den Dokus nachgucken zu müssen, wie nochmal dies und das ging/funktionierte/etc. cmake ist bestimmt toll. Ich bin nur 'n bissel faul und leicht vergesslich...



  • krümelkacker schrieb:

    Für ein Projekt habe ich auch cmake ausprobiert. So richtig klar komme ich damit aber nicht und ich finde es nervig, ständig in den Dokus nachgucken zu müssen, wie nochmal dies und das ging/funktionierte/etc. cmake ist bestimmt toll. Ich bin nur 'n bissel faul und leicht vergesslich...

    Ich hab mich vor ein paar Wochen in CMake eingearbeitet. Bis man einmal etwas zustande bringt, ist CMake wirklich extrem mühsam. Ich habe auch kaum wirklich sinnvolle Tutorials dazu gefunden, und ein Buch kaufe ich dafür sicher nicht.

    So langsam habe ich aber zumindest bei den Grundfeatures den Durchblick. Vieles ist halt immer noch unschön und erfordert teilweise etwas Boilerplate-Code, auch die Syntax ist gewöhnungsbedürftig. Aber von der Flexibilität her bin ich grundsätzlich damit zufrieden.

    Aber sofern ich nicht plattforumunabhängig entwickle (d.h. der Code muss nicht zu jeder Zeit auf jeder Plattform kompilierbar sein), benutze ich Visual Studio und Visual Assist X, das ist meiner Meinung nach sehr komfortabel. Makefiles schreibe ich nur wenns wirklich nötig ist, auf Linux ziehe ich auch fertige IDEs wie Code::Blocks vor 😉



  • Nexus schrieb:

    Ich hab mich vor ein paar Wochen in CMake eingearbeitet. Bis man einmal etwas zustande bringt, ist CMake wirklich extrem mühsam. Ich habe auch kaum wirklich sinnvolle Tutorials dazu gefunden, und ein Buch kaufe ich dafür sicher nicht.

    Ich hab mich mit gmake angefreundet. Auf der Arbeit brauche ichs eh, und für privat fand ich nmake von MS dann doch zu blöd. Wenn ich schon makefiles tippseln muss, dann gleich portable. Also benutz ich cygwin+gmake, sobald ich mehr als nur ein paar Codezeilen brauche, sprich wenn Dateien herumgeschoben werden müssen, doxygen über den Code laufen soll, Codegeneratoren im Spiel sind etc.



  • Hilfe 😕

    ich hab das ganze vor ein paar Tagen eingegeben, und mit

    g++ start -o start.cc Testprogram.cc

    compeliert und bin mir zu 99,99% sicher, dass es funktioniert hatte. Jetzt hab ichs heut wieder eingegeben, und es kommt die Fehlermeldung:

    /tmp/ccNItuC8.o: In function \_\_static\_initialization\_and\_destruction_0(int, int)': start.cc:(.text+0x45): undefined reference tostd::ios_base::Init::Init()'
    start.cc:(.text+0x4a): undefined reference to std::ios_base::Init::~Init()' /tmp/ccNItuC8.o:(.eh\_frame+0x12): undefined reference to__gxx_personality_v0'
    /tmp/ccgdpiWS.o: In function Testprogram::Testprogram()': Testprogram.cc:(.text+0x11): undefined reference tostd::cout'
    Testprogram.cc:(.text+0x16): undefined reference to std::basic\_ostream<char, std::char\_traits<char> >& std::operator<< <std::char\_traits<char> >(std::basic\_ostream<char, std::char_traits<char> >&, char const*)' Testprogram.cc:(.text+0x1e): undefined reference tostd::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)'
    Testprogram.cc:(.text+0x26): undefined reference to std::basic\_ostream<char, std::char\_traits<char> >::operator<<(std::basic\_ostream<char, std::char\_traits<char> >& (*)(std::basic\_ostream<char, std::char\_traits<char> >&))' /tmp/ccgdpiWS.o: In functionTestprogram::Testprogram()':
    Testprogram.cc:(.text+0x3d): undefined reference to std::cout' Testprogram.cc:(.text+0x42): undefined reference tostd::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
    Testprogram.cc:(.text+0x4a): undefined reference to std::basic\_ostream<char, std::char\_traits<char> >& std::endl<char, std::char\_traits<char> >(std::basic\_ostream<char, std::char_traits<char> >&)' Testprogram.cc:(.text+0x52): undefined reference tostd::basic_ostream<char, std::char_traits<char> >::operator<<(std::basic_ostream<char, std::char_traits<char> >& (*)(std::basic_ostream<char, std::char_traits<char> >&))'
    /tmp/ccgdpiWS.o: In function Testprogram::ausgabe()': Testprogram.cc:(.text+0x69): undefined reference tostd::cout'
    Testprogram.cc:(.text+0x6e): undefined reference to std::basic\_ostream<char, std::char\_traits<char> >& std::operator<< <std::char\_traits<char> >(std::basic\_ostream<char, std::char_traits<char> >&, char const*)' Testprogram.cc:(.text+0x76): undefined reference tostd::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)'
    Testprogram.cc:(.text+0x7e): undefined reference to std::basic\_ostream<char, std::char\_traits<char> >::operator<<(std::basic\_ostream<char, std::char\_traits<char> >& (*)(std::basic\_ostream<char, std::char\_traits<char> >&))' /tmp/ccgdpiWS.o: In function__static_initialization_and_destruction_0(int, int)':
    Testprogram.cc:(.text+0xa1): undefined reference to std::ios_base::Init::Init()' Testprogram.cc:(.text+0xa6): undefined reference tostd::ios_base::Init::~Init()'
    /tmp/ccgdpiWS.o:(.eh_frame+0x12): undefined reference to `__gxx_personality_v0'
    collect2: ld returned 1 exit status

    ähhhm... was bedeutet das???

    danke schon mal



  • g++ start -o start.cc Testprogram.cc

    Na das hast du hoffentlich nicht so eingegeben. Nach -o steht die Datei, in die das ausführbare Programm geschrieben wird. Wenn der Compiler soweit gekommen wäre, hätte er dir deinen Quelltext start.cc überschrieben.

    Richtig wäre:

    g++ -o start start.cc Testprogramm.cc
    

    Aber wahrscheinlich hast du gcc statt g++ genommen? Das wäre so eine typische Fehlermeldung dafür, dann fehlt nämlich die C++-Standardbibliothek beim Linken.



  • arrrrrrrrrrrgh blöder Fehler!!!

    sorry an alle und danke 🙂



  • Prometheus87_gastzugang schrieb:

    Hilfe 😕

    ich hab das ganze vor ein paar Tagen eingegeben, und mit

    g++ start -o start.cc Testprogram.cc

    probiere:
    g++ start.cc Testprogram.cc -o start



  • Und das Verb heisst "compilieren".


Log in to reply