Code Auslagerung



  • Hallo liebe Forum Leser, ich wünsche einen schönes Sonntag Nachmittag.
    So kurz zu meinem Problem ich versuche dieses echt einfache Programm zu übersetzen komme aber nicht drauf warum es nicht mehr funktioniert wenn ich es in Header Dateien auslagere?
    Alles in einer Datei überhaupt kein Problem alles in der Header Datei funktioniert auch ohne Probleme aber wenn ich die Methoden der Class in eine extra Datei stecke geht es nicht mehr.
    Naja wenn ich aber dann die Stack.cpp include geht es doch wieder aber das ist ja nicht der Sinn der Sache.
    So nun die Header Datei

    #ifndef stack_h
    #define stack_h
    
    class mystack{
    	private:
    	int *elements, sp;
    	int size;
    	public:
    	mystack(int);
    	~mystack();
    	void push(int);
    	int pop();
    	void ausgabe();
    	int get_size();
    	void set_size(int);
    };
    #endif
    

    Jetzt die stack.cpp

    #include <iostream>
    #include "stack.h"
    using namespace std;
    
    mystack::mystack(int size = 10){
    		elements = new int [size];
    		sp = 0;
    	}
    mystack::~mystack(){	
    		delete elements;
    	}
    void mystack::push(int e){
    		elements[sp++] = e;
    	}
    int mystack::pop(){
    		return elements[--sp];
    	}
    void mystack::ausgabe(){
    		for(int i = 0; i<size; ++i)
    		{
    			cout << elements[i] << endl;
    		}
    	}
    int mystack::get_size(){
    		return size;
    	}
    void mystack::set_size(int s){
    		size = s;
    	}
    

    Zu guter letzt meine main.cpp

    #include "stack.h"
    #include <iostream>
    
    int main()
    {
    	mystack *ms = new mystack;
    	ms->push(5);
    	ms->push(232);
    	ms->set_size(10);
    	ms->ausgabe();
    	cout << ms->pop() << endl;
    	cout << ms->pop() << endl;
    	delete ms;
    	return 0;
    }
    

    So die Fehler Ausgabe lautet:

    stackex.cpp: In function ‘int main()’:
    stackex.cpp:6:20: error: no matching function for call to ‘mystack::mystack()’
      mystack *ms = new mystack;
                        ^
    stackex.cpp:6:20: note: candidates are:
    In file included from stackex.cpp:1:0:
    stack.h:9:2: note: mystack::mystack(int)
      mystack(int);
      ^
    stack.h:9:2: note:   candidate expects 1 argument, 0 provided
    stack.h:4:7: note: constexpr mystack::mystack(const mystack&)
     class mystack{
           ^
    stack.h:4:7: note:   candidate expects 1 argument, 0 provided
    stackex.cpp:11:2: error: ‘cout’ was not declared in this scope
      cout << ms->pop() << endl;
      ^
    

    Der Übersetzungbefehl lautet: g++-4.9 -std=c++14 stackex.cpp -o test

    Naja ich habe jetzt echt seit 3 Stunden versucht mich selbst schlau zu machen aber ich komme einfach nicht darauf.


  • Mod

    Ein Defaultargument muss (in jeder ÜE) deklariert sein, bevor es genutzt werden kann.
    mystack::mystack(int) ist in main.cpp kein Defaultkonstruktor, denn ein Defaultargument wird dort nicht deklariert.



  • Ok ich muss zugeben ich kann dir in keiner Art und weise folgen!



  • Das Defaultargument in deinem Konstruktor darf nicht in die Implementierungsdatei (stack.cpp) sondern muss in den Header (Stack.h). Sonst weiss der Compiler in eienr anderen Datei nichts von diesem Default und gibt dir einen Fehler.

    Kleiner Tipp am Rande: Trainier dir nicht so new/ddelete Zeugs an, da gibts bessere Dinge wie std::vector oder Smart-Pointer.


  • Mod

    camper schrieb:

    Ein Defaultargument muss (in jeder ÜE) deklariert sein, bevor es genutzt werden kann.

    Der ausgeklammerte Teil gilt nur für inline Funktionen (vgl. [dcl.fct.default]/4), greift hier also nicht.
    Das oben gezeigte Programm ist ill-formed:

    <a href= schrieb:

    [dcl.fct.default]/6">
    Except for member functions of class templates, the default arguments in a member function definition that appears outside of the class definition are added to the set of default arguments provided by the member function declaration in the class definition; the program is ill-formed if a default constructor ([class.ctor]) […] is so declared.



  • @tt1991@web.de
    In der Zeile

    mystack::mystack(int size = 10)

    ist das "= 10" ein sog. Default-Argument.
    Dadurch kannst du die Funktion ohne Argumente aufrufen. So wie du das in der Zeile

    mystack *ms = new mystack;

    machst.

    Das funktioniert aber nur, wenn der Compiler das Default-Argument beim Übersetzen des .cpp Files das er gerade bearbeitet auch gesehen hat.
    Und wenn er die main.cpp deiner "aufgeteilten" Variante übersetzt, dann sieht er es aber nicht. Er sieht bloss das

    mystack(int);

    aus dem Headerfile.

    Daher die Fehlermeldung.

    Lösung:
    Nimm das "= 10" im .cpp File weg und mach es ins Header File rein.

    (Ich wusste ehrlich gesagt nichtmal dass man Default-Argumente bei der Definition überhaupt angeben darf, wenn diese ausserhalb der Klassendefinition erfolgt. Wenn Default-Argumente - wie es üblich wäre - bei der Deklaration angegeben wurden, dann darf man sie bei der Definition nämlich nicht wiederholen.)



  • Danke für die Hilfe ja vector kommt noch in der Vorlesung...

    Ja jetzt bringt er folgende Fehler:
    stackex.cpp:(.text+0xa1): Nicht definierter Verweis auf mystack::push(int)' stackex.cpp:(.text+0xb2): Nicht definierter Verweis aufmystack::push(int)'
    stackex.cpp:(.text+0xc3): Nicht definierter Verweis auf mystack::set_size(int)' stackex.cpp:(.text+0xcf): Nicht definierter Verweis aufmystack::ausgabe()'
    stackex.cpp:(.text+0xdb): Nicht definierter Verweis auf mystack::pop()' stackex.cpp:(.text+0x100): Nicht definierter Verweis aufmystack::pop()'

    Oh man warum nicht einfach alles in der Header Datei stehen kann...



  • @Arcoth
    Weisst du vielleicht wofür das gut ist dass man Default-Argumente bei einer Funktionsdefinition ausserhalb der Klassendefinition überhaupt angeben darf? MMn. macht das keinen Sinn, aber vielleicht übersehe ich da ja was.



  • @tt1991@web.de
    Heisst das .cpp File wo deine main Funktion drinnen ist jetzt main.cpp oder stackex.cpp ?

    Anyway, der Grund warum du diese neuen Fehler bekommst ist, dass du das stack.cpp File beim Übersetzen nicht mit angegeben hast. Das gehört ja auch mit zum Programm dazu, ohne das geht es nicht. g++ weiss aber nicht dass es dazugehört, so lange du es ihm nicht sagst.

    Ich übersetzt nie direkt über die Command-Line, von daher ist das jetzt geraten, aber ich würde annehmen dass es mit

    g++-4.9 -std=c++14 stackex.cpp stack.cpp -o test

    gehen sollte.



  • Naja sorry Mitglieder aber jetzt kommen neue Fehlermeldungen auch bei dem Übersetzen mit beiden cpp Dateien.
    /tmp/ccDWksal.o: In Funktion mystack::mystack(int)': stack.cpp:(.text+0x0): Mehrfachdefinition vonmystack::mystack(int)'
    /tmp/cc1qDLJB.o:stackex.cpp:(.text+0x0): first defined here
    /tmp/ccDWksal.o: In Funktion mystack::mystack(int)': stack.cpp:(.text+0x0): Mehrfachdefinition vonmystack::mystack(int)'
    /tmp/cc1qDLJB.o:stackex.cpp:(.text+0x0): first defined here
    /tmp/ccDWksal.o: In Funktion mystack::~mystack()': stack.cpp:(.text+0x4e): Mehrfachdefinition vonmystack::~mystack()'
    /tmp/cc1qDLJB.o:stackex.cpp:(.text+0x4e): first defined here
    /tmp/ccDWksal.o: In Funktion mystack::~mystack()': stack.cpp:(.text+0x4e): Mehrfachdefinition vonmystack::~mystack()'
    /tmp/cc1qDLJB.o:stackex.cpp:(.text+0x4e): first defined here
    collect2: error: ld returned 1 exit status


  • Mod

    hustbaer schrieb:

    @Arcoth
    Weisst du vielleicht wofür das gut ist dass man Default-Argumente bei einer Funktionsdefinition ausserhalb der Klassendefinition überhaupt angeben darf?

    Es entspringt der Regel, dass verschiedene Deklarationen einer Funktion die Menge der verfügbaren Default-Argumente erweitern dürfen.

    Beispiele kann ich mir durchaus vorstellen:

    class A {
        void f(A*);
    } extern a;
    
    inline void A::f(A* = &a);
    

    .. auch wenn das obige ziemlich gekünstelt aussieht. 🤡



  • Gibt es vielleicht einen weiter kompiliert Trick?



  • @Arcoth
    Naja, das (was dein Beispiel demonstriert) ist mMn. wohl nur sehr begrenzt sinnvoll. Vor allem da man ja bei Default-Argumenten auch immer Overloads mit weniger Parametern machen kann.

    @tt1991@web.de
    Kann es sein dass du jetzt die "alles in eins" Version mit der "aufgeteilten" vermischt hast?



  • Nein zu Sicherheit habe ich die alles in einem Version aus dem Ordner raus.


  • Mod

    hustbaer schrieb:

    Vor allem da man ja bei Default-Argumenten auch immer Overloads mit weniger Parametern machen kann.

    Das ist kein Argument, wenn es um die Semantik von Default Argumenten geht, weil man diese demnach ja ganz weglassen könnte.

    Was auch stimmt. Bin ich der einzige, der sie überhaupt gar nicht verwendet?



  • @Arcoth
    Doch, klar ist das ein Argument. Tu nicht immer so schwarz/weiss denken.

    Natürlich sind Default-Arguments immer ersetzbar und nie nötig.
    Sie bieten aber dennoch einen gewissen Mehrwert.

    Und ich meine halt dass es weniger schlimm ist wenn ein paar Sonderfälle nicht abgedeckt sind, wenn es einen Ausweg/Umweg gibt über den man dann auch in diesen Sonderfälle das selbe erreichen kann.


Log in to reply