Kein geeigneter Standardkonstruktor verfuegbar



  • Hallo, nach diversen Versuchen und lesen von Büchern, komme ich nicht zum Ziel. Und zwar habe ich die Basisklasse Konto. Von dieser möchte ich ein Girokonto und ein Sparkonto ableiten. Klingt ja recht einfach. Ist es ja auch eigentlich, nur gibt es noch Probleme beim Sparkonto. Fehler im main Programm: Kein geeigneter Standardkonstruktor verfuegbar.

    Ich poste hier jetzt mal die main.cpp, konto.h, konto.cpp, spar.h und spar.cpp.

    konto.h:

    #ifndef _Ckonto_
    #define _Ckonto_
    
    class Ckonto
    {
    public:
    	int kontonummer;
    	float kontostand;
    	char *name;
    protected:
    	Ckonto(int knr, char *n, float kstd);
    	~Ckonto();
    
    	virtual void einzahlen(float betrag) = 0;
    	virtual void auszahlen(float betrag) = 0;
    	virtual void ueberweisen(Ckonto *k2, float betrag) = 0;
    	virtual void erstellen(int knr)= 0;	
    
    	int getkontonummer();
    	float getkontostand();
    	char getname();
    
    	void schreibeKonto(char * fname);
    	void leseKonto(char * fname);
    };
    #endif
    

    konto.cpp:

    #include "konto.h"
    #include "iostream.h"
    #include "string.h"
    #include "fstream.h"
    
    	int kontonummer;
    	float kontostand;
    	char *name;
    
    Ckonto::Ckonto(int knr=123, char *n="abc", float kstd = 0.0f)
    	{
    		kontonummer = knr;
    		kontostand = 0;
    		int l = strlen(n);
    		name = new char[strlen(n)+1];
    		strcpy(name, n);
    	}
    
     Ckonto::~Ckonto()
    	{
    		delete [] name;
    	}
    
    	void Ckonto::schreibeKonto(char * fname)				
    	{
    		ofstream schreibe;							
    		schreibe.open( fname, ios::out );			
    		schreibe << "Kontonummer :" << kontonummer << "\n";	
    		schreibe << "Kontoinhaber:" << name << "\n";		
    		schreibe << "Kontostand  :"  << kontostand << "\n";	
    		schreibe.close();								
    	}
    
    	void Ckonto::leseKonto(char * fname)				
    	{
    		ifstream lese;							
    		lese.open( fname, ios::in );			
    		lese >> kontonummer >> name >> kontostand;  
    		lese.close();							
    	}
    
    	int getkontonummer()
    	{
    		return kontonummer;
    	}
    
    	float getkontostand()
    	{
    		return kontostand;
    	}
    
    	char getname()
    	{
    		return *name;
    	}
    

    spar.h:

    #ifndef _spar_
    #define _spar_
    
    #include "konto.h"
    
    class spar : public Ckonto 
    {
    public:
    	spar(int knr, char *n, float kstd, float p);
    
    	void erstellen(int knr);
    	void einzahlen(float betrag);
    	void auszahlen(float a);
    	void ueberweisen(Ckonto *k2, float betrag);
    
    };
    #endif;
    

    spar.cpp:

    #include "spar.h"
    #include "iostream.h"
    #include "string.h"
    #include "fstream.h"
    #include "konto.h"
    
    float praemie;
    
    spar::spar(int knr=123, char *n="abc", float kstd = 0.0f, float p = 10.0f) : Ckonto(knr, n, kstd)
    	{		
    		praemie = p;
    		kontostand = kontostand+praemie;	
    	}
    
    void spar::erstellen(int knr)
    {
    	char kname[50];
    	cout << "Bitte geben Sie Ihren Namen ein: ";
    	cin >> kname;
    	kontonummer = knr;
    	delete[]name;
    	name=new char[strlen(kname)+1];
    	strcpy(name,kname);
    }	
    
    void spar::einzahlen(float betrag)
    {
    	kontostand = kontostand + betrag;	
    }
    
    void spar::auszahlen(float a)
    {
    	if((kontostand - a) < 0)						
    		cout << "Fehler, gehen Sie arbeiten!";
    	else
    		kontostand = kontostand - a;
    }
    
    void spar::ueberweisen(Ckonto *k2, float betrag)
    {
    	if((kontostand - betrag) < 0)					
    		cout << "Fehler, gehen Sie arbeiten!";		
    	else
    	{
    		auszahlen(betrag);
    		k2->einzahlen(betrag);
    	}
    }
    

    main.cpp:

    #include "functions.h"
    #include "konto.h"
    #include "giro.h"
    #include "spar.h"
    #include "string.h"
    #include "iostream.h"
    #include "windows.h"
    
    void main()
    {
    	int wahl;
    	int knr1=1;
    	int knr2=2;
    	int knr3=3;
    
    	int knr4=4;
    	float betrag=0;
    	float betrag2=0;
    
    	giro daten;
    	giro daten2;
    	spar a;
    	spar b;
    //Menü für den Benutzer. Entsprechend werden die Kontonummer und Kontoart in den "()" übergeben. 
    	do
    	{
    		wahl=menu();
    		switch(wahl)
    		{
    			case 1: if(abfrage()==1) 
    						girokonto_erstellen(daten,&knr1);
    					else
    						sparkonto_erstellen(a, &knr2);
    				break;
    			case 2: if(abfrage()==1) 
    						girokonto_erstellen(daten2,&knr3);
    					else
    						sparkonto_erstellen(b, &knr4);
    				break;
    			case 3: if(abfrage()==1) 
    						kontstand_abrufen(daten,daten2);
    					else
    						kontstand_abrufen(a, b);
    				break;
    			case 4: if(abfrage()==1) 
    						ueberweisen(daten, daten2, betrag);
    
    					else
    						ueberweisen(a, b, betrag);					
    				break;
    			case 5: if(abfrage()==1) 
    						einzahlen(daten, daten2, betrag);
    					else
    						einzahlen(a, b, betrag);					
    				break;			
    			case 6: if(abfrage()==1) 
    						auszahlen(daten, daten2, betrag);
    					else
    						auszahlen(a, b, betrag);
    				break;
    		}
    	} while(wahl< 7);
    
    	daten.schreibeKonto("Girokonto1.txt");
    	daten2.schreibeKonto("Girokonto2.txt");		
    	a.schreibeKonto("Sparkonto1.txt");		
    	b.schreibeKonto("Sparkonto2.txt");		
    
    	beenden();
    }
    

    Die Programmteile dürften reichen. Die functions.cpp dürfte nicht von bedeutung sein. Ich nehme mal an der Fehler liegt in der spar.h bzw. spar.cpp...

    Sebastian



  • Sebastian08 schrieb:

    Fehler im main Programm: Kein geeigneter Standardkonstruktor verfuegbar.

    Das ist mit Sicherheit nicht die vollständige Fehlermeldung (In der Regel steht dort noch Zeilennummer, Datei... Zumindestens bei allen mir bekannten Compiler.

    Und ganz ehrlich ist es nicht unsere Aufgabe dann deinen Code zu linken um eben diese Fehlermeldung zu erhalten.



  • Ich habe ja auch nirgendwo gesagt das ihr meinen Code ausführen müsst um die Meldung zu erhalten.

    Aber sie ist wirklich so.

    error C2512: 'spar' : Kein geeigneter Standardkonstruktor verfuegbar



  • Wenn du deinen Code nochmal soweit reduzierst dass nur das Wesentliche drin steht wird sich vielleicht jemand erbarmen sich den durchzulesen.

    zur Fehlermeldung: "kein Standardkonstruktor verfügbar" kommt, wenn du eine Klasse hast, die keinen Default-Ctor hat und versuchst, ein Obejkt davon direkt oder indirekt ohne Argumente zu initialisieren.

    Der default-Ctor ist der Konstruktor, der ohne Argumente aufgerufen werden kann, entweder weil er keine hat, oder weil ein Konstruktor exisitert der für jedes Argument einen Defaultwert hat. Der default-Ctor wird häufig vom Compiler generiert, allerdings nur, wenn du selbst keinen anderen Ctor deklarierst. letzteres scheint der Fall zu sein, sah zumindest beim Überfliegen deines Codes so aus.
    Initialisierungen ohne Argumente eines Objekts vom Typ T können wie folgt zustandekommen:
    - du deklarierst eine Variable ohne Konstruktorargumente und ohne ein = xyz; dahinter
    - du rufst den Defaultkonstruktor explizit auf: T(); oder T x = new T();
    - du erzeugst ein Array von T's, statisch oder dynamisch: T array[12]; oder T* pT = new T[16];
    - irgendeine Bibliothek tut eins der oben genannten Dinge hinter den Kulissen (z.B. std::vector macht das)
    - im Konstruktor einer Klasse die ein T-Member hat (oder von T abgeleitet wurde) rufst du keinen anderen Konstruktor von T in der Initialisierungsliste auf

    letzteres ist vermutlich dein Fehler. Einem Member erst im Konstruktorbody etwas zuzuweisen ist keine Initialisierung, alle Member und Basisklassen werden VOR Eintritt in den Ctor-Body konstruiert - wenn in der Initialisierungsliste kein expliziter Aufruf steht wird der Default-Ctor aufgerufen.



  • Sebastian08 schrieb:

    Aber sie ist wirklich so.

    error C2512: 'spar' : Kein geeigneter Standardkonstruktor verfuegbar

    Und dieser Fehler ist auch logisch... (Wobei ich noch immer nicht glaube das keine Zeilennummer/Datei usw kommt.

    spar a;
    

    Geht nur wenn eben dieser definiert ist. Der Compiler wird ja wohl kaum raten können was er an dieser Stelle übergeben soll (Du hast spar(int knr, char *n, float kstd, float p); als einzigen Konstruktor vorgesehen).



  • Hi,

    ich jetzt nur mal schnell drüber geflogen und konnte nichts genaues erkennen was den Compiler stört.

    Was du aber wissen solltest ist, dass wenn der Compiler auf das Wort class trifft legt er, falls du es nicht machst, automatisch einen Konstruktor, Destruktor, Standardkopierkonstruktor und Zuweisungsoperator an. Konstruktor und Destruktor hast du deklariert und vermutlcih auch definiert.

    Was ich allerdings komisch fande, war die Deklarartion von konto.h.

    Versuche es mal mit:

    #ifndef CKONTO_H_INCLUDED
    #define CKONTO_H_INCLUDED
    
    class Ckonto
    {
    public:
        Ckonto(int knr, char *n, float kstd);
        ~Ckonto();
    
        virtual void einzahlen(float betrag) = 0;
        virtual void auszahlen(float betrag) = 0;
        virtual void ueberweisen(Ckonto *k2, float betrag) = 0;
        virtual void erstellen(int knr)= 0;   
    
        int getkontonummer();
        float getkontostand();
        char getname();
    
        void schreibeKonto(char * fname);
        void leseKonto(char * fname);
    
    protected:
        int kontonummer;
        float kontostand;
        char *name;
    
    private:
        Ckonto( const Ckonto& );
        Ckonto& operator=( const Ckonto& ); 
    };
    #endif
    

    Konstruktor und Destruktor sind public. Standardkopierkonstruktor und Zuweisungsoperator private. Sollte es nun zu einer Nutzung des Standardkopierkonstuktor kommens wird der Compiler etwas genauer daraufhin weisen. Auch sind die Membervariablen protected. Wobei ich aber denke, dass war vielleicht mehr ein Fehler von dir.

    Gruß
    Lord Hong



  • Ach ja, jetzt sehe ich es auch. Mein Vorposter hat recht.

    spar a;
    spar b;
    
    spar(int knr, char *n, float kstd, float p);
    

    Da fehlen natürlich die Argumente.

    spar a( 4711, "Hello", 12.0, 1.0 );
    

    So wird es klappen. 😉



  • Mit dem Codestück von lord.hong funktioniert es zwar, aber wohl die letzten Fehler wenn ich es ausführen möchte:

    main.obj : error LNK2001: Nichtaufgeloestes externes Symbol "public: __thiscall giro::giro(int,char *,float)" (??0giro@@QAE@HPADM@Z)
    Debug/bkvs.exe : fatal error LNK1120: 1 unaufgeloeste externe Verweise
    

    Sowas liebe ich ja...wenn ich auf den Fehler klicke, komme ich nicht zur Stelle wo der Fehler ist.



  • Sebastian08 schrieb:

    Sowas liebe ich ja...wenn ich auf den Fehler klicke, komme ich nicht zur Stelle wo der Fehler ist.

    Ist auch ein Linkerfehler, der findet keine entsprechende Stelle im Code. Der Fehler besagt, dass du eine Funktionsdefinition vergessen hast (der giro::giro() -Konstruktor).



  • Programm läuft soweit, nur wenn ich die Werte bei spar a im main programm mitgebe, ist ja mein standardkonstruktor überflüssig.

    die konto.h und konto.cpp habe ich ja bereits im ersten post stehen.



  • Sebastian08 schrieb:

    Programm läuft soweit, nur wenn ich die Werte bei spar a im main programm mitgebe, ist ja mein standardkonstruktor überflüssig.

    Logisch. Da man aber in der Regel Variablen erst deklariert wenn man diese verwendet, hätte man die Problematik vielleicht auch gänzlich vermeiden können...



  • Erstmal sorry, für meinen übereilten Beitrag gestern, ich habe Standardkopierkonstruktor gelesen.

    Sebastian08 schrieb:

    Programm läuft soweit, nur wenn ich die Werte bei spar a im main programm mitgebe, ist ja mein standardkonstruktor überflüssig.

    die konto.h und konto.cpp habe ich ja bereits im ersten post stehen.

    In deinem Fall legt der Kompilier keinen Standardkonstruktor an. Der Grund liegt in der Definition von spar. Die lautet:

    spar(int knr, char *n, float kstd, float p);
    

    Somit hast du dem Kompilier mitgeteilt wie du das Objekt erzeugen möchstest. Er wird nun auch keinen weitern Konstruktor erzeugen.

    Zum besseren Verständnis (mehr oder weniger Scott Meyer wieder gegeben.)

    class CEmpty
    {
    };
    

    Diese Klasse sieht im ersten Moment leer aus, in Wirklichkeit ist aber der C++ Kompiler ziemlich aktiv geworden.

    Um das Objet zu erzeugen, muss einen Konstruktor erzeugen. Wenn du es nicht machst, macht der Kompilier es für dich. Um das Objekt zu zerstören, legt einer einen Destruktor an, wenn du es nicht macht, macht er es automatisch und ohne zu fragen oder hinzuweisen.
    Wenn du ein Objekt vom Typ CEmpty einen Wert zuweisen möchtest und hast keinen Zuweisungsoperator definiert, macht der Kompiler es für dich und kopiert, falls ich mich noch richtig erinnere, bitweise (was bei Zeigern, const und Referenzen zu Problemen führen kann). So ähnlich verhält sich auch der Standardkopierkonstruktor.

    Des Wegen kann der Compiler auch diesen Code ausführen:

    {
     CEmpty e; // Konstruktor
     CEmpty f( e ); // Kopierkonstruktor
     f = e; // Zuweisungsoperator
    } // Destruktor für e und f
    

    Das solltest du bei C++ immer im Hinterkopf haben, das ist "dein tägliches Brot" (um Scott Meyers Wort wörtlich zu zitieren)!

    Gruß
    Lord Hong



  • das noch niemand die Standard-Fehler wie void main() und iostream.h bemaengelt hat 🤡



  • zwutz schrieb:

    das noch niemand die Standard-Fehler wie void main() und iostream.h bemaengelt hat 🤡

    Vermutlich liegt das nur daran, das so lange Quelltexte im Forum ungern wirklich gelesen werden 😉 (Ich habe z.B. auch nur nach der vom Compiler angemeckerten Stelle gesucht)...

    Aber um es nachzuholen:
    Weder void main() noch iostream.h sind C++... (@zwutz: Damit sollte das soll erfüllt sein ;p).

    cu André


Anmelden zum Antworten