Nochmals Klassen

drpingoo

Erfahrenes Mitglied
Hallo zusammen!

ich habe da folgende Aufgabe:

Schreiben Sie die Klasse SIMcard mit den nachfolgend beschriebenen Eigenschaften.
Verwenden Sie dabei den unten gegebenen Typ Eintrag, in dem jeweils ein Name mit einer
Telefonnummer gespeichert wird.
· Die Klasse hat als private Elemente ein Telefonbuch vom Typ vector<Eintrag> und
die PIN (Sperrcode) als int-Zahl.
· Der Konstruktor besitzt einen Referenzparameter vom Datentyp int, in dem die PIN der
SIMcard gespeichert wird.
· Die öffentliche Methode trageEin vom Typ bool trägt in das Telefonbuch einen
neuen Eintrag ein. Übergabeparameter sind ein Name, eine Telefonnummer sowie die
PIN. Bei Angabe eine falschen PIN wird kein Eintrag vorgenommen und die Methode
gibt den Wert false zurück, ansonsten true.
· Die öffentliche Methode sucheNummer vom Typ int sucht die zu einem Namen
gehörige Telefonnummer im Telefonbuch. Die Suche wird nur durchgeführt, wenn die
übergebene PIN derjenigen der SIMcard entspricht. Die Methode gibt den Wert 0 zurück,
wenn kein Eintrag vorhanden ist und -1, wenn die übergebene PIN falsch ist.

Ich habe dazu mal folgendes Programm geschrieben:
Code:
#include <iostream>
#include <vector>
#include <string>
using namespace std;



struct Eintrag{
	string name; 
	int nummer;
};

class simcard{
private:
	vector<Eintrag> ein;
	int PIN;

public:
	simcard(); //Default Konstruktor
	int Set_PIN(int pin); //Set-Methode
	bool trageEin(string Name, int Telnr, int pin);
	int sucheNummer();
	};

simcard::simcard(){

	PIN = 0;
	Eintrag eintrag;
	eintrag.name = " ";
	eintrag.nummer = 0;
	 

}

bool simcard::trageEin(string Name, int Telnr, int pin){//Überprüft, ob PIN korrekt ist, 
	if(PIN==pin){										//wenn ja, Person ins Tel.buch eintragen
		Eintrag eintrag2;
		eintrag2.name = Name;
		eintrag2.nummer = Telnr;
		ein.push_back(eintrag2);
		
		Eintrag front = ein.front();//das ist bloss dazu da, damit
		string f =front.name;		//ich kontrollieren kann, wie viele 
		int anzahl =ein.size();		//Elemente ich in vector<Eintrag> besitze
		cout << anzahl << endl;
		cout << "wahr " << f  << endl;
return true;
}
	else{
		cout <<"falsch" << endl;
		return false;
	}
}
int simcard::Set_PIN(int pin){

	PIN = pin;
	return PIN;

}

int simcard::sucheNummer(){
	if(trageEin(string Name, int Telnr, int pin)
	{

		
		return 0;}
	else {
		return -1;}
}

int main(){

	simcard sim;
	sim.Set_PIN(456);
	cout << sim.Set_PIN(456) << endl;

	sim.trageEin("Meier", 5620126, 456);

	simcard sim2;
	sim2.Set_PIN(123);
	cout << sim.Set_PIN(123) << endl;

	
	sim2.trageEin("Müller", 5233352, 123);
	sim.sucheNummer();



	return 0;}

Ich habe da nun 2 Probleme.

Das erste ist, dass ich komischerweise immer 1 zurückbekomme, wenn ich nach ein.size (der vector<Eintrag> heisst ein) frage. Beim ersten Mal leuchtet mir das ja ein, aber wenn ich das zweite mal durchgehe, also mit "Müller", da sollten doch 2 Elemente drin sein...
EDIT: Mein Gedanke dahinter ist, dass ich eine for-Schleife dann solange laufen lasse, bis ich durch alle Elemente durchgegangen bin und die Nummer entweder gefunden habe oder nicht.

Das zweite bezieht sich aud die sucheNummer-Fkt. Ich habe ja einen bool, der überprüft, ob die Pin-Eingabe korrekt war oder nicht. Nun würde ich gerne diese Fkt. ebenfalls in der if-Abfrage verwenden, als Übergabeparameter hab ich einfach dieselben genommen, wie immer, aber da motzt der Compiler (Ungültige Verwendung dieses Typs als Ausdruck).
Was müsste dann stattdessen dastehen und wieso versteh er es so nicht?

lg
 
Zuletzt bearbeitet:
Hi.

Verschiedene Sachen:

  1. Warum hat die Klasse einen Default Konstruktor? In der Aufgabe stand nichts davon und meiner Meinung nach macht es auch nicht viel Sinn.
  2. Der Code im Default Konstruktor ist unsinnig: Du legst eine lokale Variable an und initialisierst diese Variable mit Standardwerten. Die Variable existiert nur im Konstruktor und ist deshalb überflüssig. Außerdem sollte man Membervariablen möglichst in der Initialisierungsliste des Konstruktors initialisieren.
  3. Wo ist der Konstruktor von dem in der Aufgabe die Rede war?
  4. Wozu gibt es die Methode Set_PIN - davon stand nichts in der Aufgabe! Die PIN soll ausschließlich im Konstruktor gesetzt werden können. Was nützt die PIN, wenn man sie direkt ändern kann?
  5. Warum rufst du innerhalb der sucheNummer Methode die Methode trageEin auf? Die Methode sucheNummer sollte const sein. Es darf in der Methode kein Eintrag hinzugefügt werden!
  6. Du hast bei der if-Abfrage in der sucheNummer Methode eine schließende Klammer vergessen, deshalb beschwert sich der Compiler...
  7. Du hast 2 Simkarten Objekte, in eins hast du Meier eingefügt, in das andere Müller. Preisfrage: Wieviele Einträge sind in sim, wieviele in sim2? ;)
 
Ah, ja logisch. Einen Eintrag in sim und eine in sim2;).

Zum Default-Konstruktor, das ist richtig, es wird nicht nach einer Set_Pin-Methode verlangt und ich hätte das stattdessen auch mit dem Konstruktor machen können, wäre so wahrscheinlich auch schöner... Ich hab mich jedoch für die Set_Pin-Methode entschieden. Ein Default-Konstruktor wir ja sowieso vom Compiler erzeugt, deshalb kommt es ja nicht darauf an, ob ich den noch explizit hinschreibe oder mich auf den Compiler verlasse.

2 deiner Aussagen hab ich jedoch nicht ganz verstanden.
Wozu gibt es die Methode Set_PIN - davon stand nichts in der Aufgabe! Die PIN soll ausschließlich im Konstruktor gesetzt werden können. Was nützt die PIN, wenn man sie direkt ändern kann?

Man kann sie ja schon nicht direkt ändern, sondern muss über die SET_Pin-Methode gehen. Ich hab das eben zuerst mit Set und Get-Methoden gelernt und danach, dass man das auch mit Konstruktoren angehen kann. Ist doch so, wies bei mir steht, schon nicht falsch, oder?

Warum rufst du innerhalb der sucheNummer Methode die Methode trageEin auf? Die Methode sucheNummer sollte const sein. Es darf in der Methode kein Eintrag hinzugefügt werden!

Ich merke gerade, dass das sinnlos ist. Ich weiss grad auch nicht mehr, was ich mir dabei überlegt hab... Geht das mit dem const aus dem Text hervor oder muss man da selbst drauf kommen? Wenn ich jetzt nicht die Methode trageEin da verwende (wie gesagt, hab vergessen, was ich eigtl damit wollte), muss die Methode sucheNummer ja nicht unbedingt const sein.

Ja, das mit dem if... Dummer Fehler, würd ich mal sagen. Ich dachte aber eigtl, dass es auch mit Klammer da nicht funktionierte und einen Fehler ausspuckte. Muss ich nochmals ausprobieren, bin eben gerade nicht an dem Computer, wo ich meine Programme draufhabe.

lg
 
Zuletzt bearbeitet:
Zum Default-Konstruktor, das ist richtig, es wird nicht nach einer Set_Pin-Methode verlangt und ich hätte das stattdessen auch mit dem Konstruktor machen können, wäre so wahrscheinlich auch schöner... Ich hab mich jedoch für die Set_Pin-Methode entschieden. Ein Default-Konstruktor wir ja sowieso vom Compiler erzeugt, deshalb kommt es ja nicht darauf an, ob ich den noch explizit hinschreibe oder mich auf den Compiler verlasse.
Das ist nicht richtig. Wenn du einen eigenen (nicht-Default) Konstruktor definierst, definiert der Compiler keinen Default-Konstruktor.

Man kann sie ja schon nicht direkt ändern, sondern muss über die SET_Pin-Methode gehen. Ich hab das eben zuerst mit Set und Get-Methoden gelernt und danach, dass man das auch mit Konstruktoren angehen kann. Ist doch so, wies bei mir steht, schon nicht falsch, oder?
Es ging mir auch nicht um die generelle Vorgehensweise zum Ändern einer Membervariablen (über set/get Methoden), sondern um die Logik der Implementation an sich. Was nützt der beste Sperrmechanismus, wenn man den Sperrmechanismus einfach aushebeln kann, indem man das Passwort neu setzt?!
C++:
void foo(simcard& sc) {
  sc.SET_Pin(0);
  sc.trageEin("paul", 0444, 0);
}
Geht das mit dem const aus dem Text hervor oder muss man da selbst drauf kommen? Wenn ich jetzt nicht die Methode trageEin da verwende (wie gesagt, hab vergessen, was ich eigtl damit wollte), muss die Methode sucheNummer ja nicht unbedingt const sein.
Das sollte sie aber. Die Methode darf (rein logisch) keine Änderungen an einem Objekt der Klasse vornehmen, da es sich nur um eine Suche handelt. Wenn du ein konstantes Simcard Objekt hast, kannst du nur konstante Methoden aufrufen. Und ja, da muß man selbst drauf kommen, das war in der Aufgabe nicht explizit gefordert... (wäre allerdings guter Stil)

Gruß
 
C++:
#include <iostream>
#include <vector>
#include <string>

class SimCard
{
public:
    struct Entry
    {
        std::string name; 
        unsigned int number;
        
        Entry(std::string const& name, const unsigned int number)
            : name(name), number(number)
        {}
        const bool operator==(std::string const& name) const { return this->name == name; }
    };
private:
	std::vector<Entry> m_phonebock;
	unsigned int m_identification;

public:
	SimCard()
            : m_identification(1234U)
        {}

public:
        void set_identification(const unsigned int id) { m_identification = id; }
        const bool add_entry(const unsigned int id, Entry const& entry)
        { 
                if (m_identification != id) return false;
                m_phonebock.push_back(entry);
                return true;
        }

	const unsigned int find_number(std::string const& name) const 
        { 
                std::vector<Entry>::const_iterator it(std::find(m_phonebock.begin(), m_phonebock.end(), name));
                if (it == m_phonebock.end()) throw std::invalid_argument("unknown person");
                return (*it).number;
        }
};
so isset doch machbar ;)
 
Danke für eure Antworten. Ja, das mit dem Konstruktor weiss ich eigtl, aber kann ja nichts schaden, wenn du mich nochmals darauf hinweist.

@devDevil
Danke, für den Code, muss ihn mir einfach mal noch genauer zu Gemüte führen, du scheinst eine Vorleibe zu haben den using namespace std wegzulassen;).
 
Das Weglassen dieser Zeile ist manchmal ganz praktisch, wenn du eine Klasse oder ein struct mit dem selben Namen haben willst wie er schon im std-Namespace vorkommt.
 
Zurück