Zugriff auf Methode über Klasse

Hey, ich versuche gerade über die Klasse auf eine Methode zuzugreifen, aber anscheinend läuft das in C++ etwas anders als in Java. Ich kriegs jedenfalls nicht hin.

speicher ist ein Vector gefüllt mit Objekten und die Methode soll einfach nur die Objekte ausgeben

fahrzeug.cpp:
Code:
// Array Ausgabe
void Fahrzeug::printVectorItems() {
	std::cout << "--- Ihr Fahrzeugbestand ---" << std::endl;
	if (!speicher.size() == 0) {
		for (unsigned int i = 0; i < speicher.size(); i++) {
			std::cout << "--------------------------" << std::endl;
			std::cout << "Fahrzeug " << i << std::endl;
			std::cout << "Name:    " << speicher.at(i).fName << std::endl;
			std::cout << "Typ:     " << speicher.at(i).fType << std::endl;
			std::cout << "Gewicht: " << speicher.at(i).fWeight << std::endl;
		}
	}
}

Aus der main.cpp:
Code:
		break;
			// Bestehendes Fahrzeug löschen
		case 2:
			Fahrzeug::printVectorItems();
			break;
		case 3:
			break;

So gehts nicht, er will ein Objekt haben und nicht die Klasse. Hab diverse Varianten mit "static" versucht. Nur die Methode, nur den Vector und beides aber er bringt mir meistens den Fehler "cannot declare member function `static void Fahrzeug::printVectorItems()' to have static linkage". Bin grad echt etwas ratlos. In Java müsste ich doch nur die Methode static machen und könnte dann über die Klasse drauf zugreifen Wie ist das bei C++?
 
Eigentlich auch so.
Man muss halt (wie in Java) aufpassen, dass man in der static-Methode keine nonstatic-Attribute der Klasse verwendet.
Woher kommt den speicher? Wenn er auch in der Klasse ist, muss er dann auch static sein.
Zeig am besten mal die ganze Klasse

PS: Das ewige std:: kann man sich mit einem
using namespace std;
am Dateianfang sparen.
 
Fahrzeug.cpp

Code:
#include "Fahrzeug.h"
#include <iostream>

// Konstruktor
Fahrzeug::Fahrzeug(std::string fName, double fWeight, std::string fType) {

	Fahrzeug::setName(fName);
	Fahrzeug::setWeight(fWeight);
	Fahrzeug::setType(fType);
	std::cout << "Ein neues Fahrzeug wurde angelegt" << std::endl;

}

// Destruktor
Fahrzeug::~Fahrzeug() {
}

// Speicherverwaltung
void Fahrzeug::addFahrzeugToVector() {
	speicher.push_back(*this);
}
void Fahrzeug::removeFahrzeugFromVector(int fIndex) {
	speicher.erase(speicher.begin() + fIndex);
}

// Array Ausgabe
static void Fahrzeug::printVectorItems() { <-- hier Fehlermeldung
	std::cout << "--- Ihr Fahrzeugbestand ---" << std::endl;
	if (!Fahrzeug::speicher.size() == 0) {
		for (unsigned int i = 0; i < Fahrzeug::speicher.size(); i++) {
			std::cout << "--------------------------" << std::endl;
			std::cout << "Fahrzeug " << i << std::endl;
			std::cout << "Name:    " << Fahrzeug::speicher.at(i).getName() << std::endl;
			std::cout << "Typ:     " << Fahrzeug::speicher.at(i).getType() << std::endl;
			std::cout << "Gewicht: " << Fahrzeug::speicher.at(i).getWeight() << std::endl;
		}
	}
}

// Getter und Setter Methoden
void Fahrzeug::setName(std::string name) {
	fName = name;
}

void Fahrzeug::setWeight(double weight) {
	fWeight = weight;
}

void Fahrzeug::setType(std::string type) {
	fType = type;
}

std::string Fahrzeug::getName() {
	return fName;
}

double Fahrzeug::getWeight() {
	return fWeight;
}

std::string Fahrzeug::getType() {
	return fType;
}

Fahrzeug.h
Code:
#include <vector>
#include <iostream>


/**
 * Klasse zum Erstellen eines Fahrzeugobjektes inklusive aller nötigen Methoden
 */
class Fahrzeug {

private:
	// Fahrzeugname
	std::string fName;
	// Fahrzeuggewicht
	double fWeight;
	// Fahrzeugtyp
	std::string fType;
	// Fahrzeugspeicher
	static std::vector<Fahrzeug> speicher;
public:
	void setName(std::string);
	void setWeight(double);
	void setType(std::string);
	void addFahrzeugToVector();
	void removeFahrzeugFromVector(int);
	static void printVectorItems();
	std::string getName();
	double getWeight();
	std::string getType();
	// Konstruktor und Destruktor
	Fahrzeug(std::string, double, std::string);
	~Fahrzeug();

};

Fehler: cannot declare member function `static void Fahrzeug::printVectorItems()' to have static linkage

Ich checks nicht ganz, wo da jetzt der Fehler liegt
 
Hallo Alex,

du musst in der Fahrzeug.cpp das static weglassen. Außerdem musst du den statischen Member speicher irgendwo definieren, am besten in der Fahrzeug.cpp:
C++:
std::vector<Fahrzeug> Fahrzeug::speicher;

Desweiteren solltest du darauf achten, bei Headerdateien stets einen Include-Wächter zu verwenden.

<edit>
Noch ein paar Anmerkungen:

PS: Das ewige std:: kann man sich mit einem
using namespace std;
am Dateianfang sparen.
Das ist richtig, allerdings sollte man das in einer Header-Datei nie machen. Stichwort "namespace pollution".

Code:
// Speicherverwaltung
void Fahrzeug::addFahrzeugToVector() {
	speicher.push_back(*this);
}
Bist du dir bewusst, dass hier wird eine Kopie deines Objektes angelegt wird? Möglicherweise ist das nicht das, was du beabsichtigst.

Code:
// Array Ausgabe
static void Fahrzeug::printVectorItems() { <-- hier Fehlermeldung
	std::cout << "--- Ihr Fahrzeugbestand ---" << std::endl;
	if (!Fahrzeug::speicher.size() == 0) {
		for (unsigned int i = 0; i < Fahrzeug::speicher.size(); i++) {
			std::cout << "--------------------------" << std::endl;
			std::cout << "Fahrzeug " << i << std::endl;
			std::cout << "Name:    " << Fahrzeug::speicher.at(i).getName() << std::endl;
			std::cout << "Typ:     " << Fahrzeug::speicher.at(i).getType() << std::endl;
			std::cout << "Gewicht: " << Fahrzeug::speicher.at(i).getWeight() << std::endl;
		}
	}
}
Dass "!Fahrzeug::speicher.size() == 0" hier das gewünschte Ergebnis liefert, ist vermutlich nur Zufall. Der Ausdruck ist nämlich äquivalent zu "(!Fahrzeug::speicher.size()) == 0". Wahrscheinlich wolltest du aber "!(Fahrzeug::speicher.size() == 0)" haben. Du musst den Ausdruck also entweder so klammern oder besser den passenden Operator verwenden: "Fahrzeug::speicher.size() != 0". Die if-Abfrage ist aber sowieso überflüssig.

Zur for-Schleife: Um alle Elemente eines Vektors zu durchlaufen, verwendet man (ähnlich wie in Java) in der Regel Iteratoren. Das sähe dann so aus:
C++:
void Fahrzeug::printVectorItems() {
	std::cout << "--- Ihr Fahrzeugbestand ---" << std::endl;
	std::vector<Fahrzeug>::iterator it = Fahrzeug::speicher.begin();
	for (int i = 0; it != Fahrzeug::speicher.end(); ++it, ++i) {
		std::cout << "--------------------------" << std::endl;
		std::cout << "Fahrzeug " << i << std::endl;
		std::cout << "Name:    " << it->getName() << std::endl;
		std::cout << "Typ:     " << it->getType() << std::endl;
		std::cout << "Gewicht: " << it->getWeight() << std::endl;
	}
}

Code:
// Getter und Setter Methoden
void Fahrzeug::setName(std::string name) {
	fName = name;
}
Aus Performance-Überlegungen wäre es hier (und in den anderen Settern sowie im Konstruktor) besser, den String als const-Referenz zu übergeben. Sonst muss der String möglicherweise zweimal umkopiert werden (einmal beim Aufruf des Setters und ein zweites mal bei der Zuweisung).
</edit>

Grüße,
Matthias
 
Zuletzt bearbeitet:
Hi.
Gibt es einen Grund, warum du hier ++it und ++i verwendest und nicht it++ und i++, oder ist das nur persönliche Gewohnheit?
Es ist eine gute Angewohnheit, da Präinkrementoperatoren effizienter implementiert werden können als Postinkrementoperatoren.

Wenn man den Rückgabewert des Operators nicht benötigt, sollte man immer die Präinkrementoperatoren wählen.

Gruß
 
Zuletzt bearbeitet:
Bei i++ wird mit dem alten Wert weitergerechnet, der Wert wird erst nach der Anweisung erhöht.
Bei ++i Wird sofort mit dem inkrementierten Wert weitergemacht.

zb:
C++:
int i=1;
printf("%d",i++);
printf("%d",i);
ergibt: 1,2

C++:
int i=1;
printf("%d",++i);
printf("%d",i);
ergibt: 2,2
 
Bist du dir bewusst, dass hier wird eine Kopie deines Objektes angelegt wird? Möglicherweise ist das nicht das, was du beabsichtigst.

Theoretisch geht das ja schon, aber eigentlich wollte ich das aktuell erstellte Objekt in den Vector einfügen und nicht eine Kopie. Komme allerdings damit nicht so richtig klar bisher...

Dass "!Fahrzeug::speicher.size() == 0" hier das gewünschte Ergebnis liefert, ist vermutlich nur Zufall. Der Ausdruck ist nämlich äquivalent zu "(!Fahrzeug::speicher.size()) == 0". Wahrscheinlich wolltest du aber "!(Fahrzeug::speicher.size() == 0)" haben. Du musst den Ausdruck also entweder so klammern oder besser den passenden Operator verwenden: "Fahrzeug::speicher.size() != 0". Die if-Abfrage ist aber sowieso überflüssig.

Jo, Klammerfehler und überflüssige Abfrage ... verstanden ... danke :)

Zur for-Schleife: Um alle Elemente eines Vektors zu durchlaufen, verwendet man (ähnlich wie in Java) in der Regel Iteratoren. Das sähe dann so aus:
C++:
void Fahrzeug::printVectorItems() {
	std::cout << "--- Ihr Fahrzeugbestand ---" << std::endl;
	std::vector<Fahrzeug>::iterator it = Fahrzeug::speicher.begin();
	for (int i = 0; it != Fahrzeug::speicher.end(); ++it, ++i) {
		std::cout << "--------------------------" << std::endl;
		std::cout << "Fahrzeug " << i << std::endl;
		std::cout << "Name:    " << it->getName() << std::endl;
		std::cout << "Typ:     " << it->getType() << std::endl;
		std::cout << "Gewicht: " << it->getWeight() << std::endl;
	}
}

Hmm...in Java nie benutzt, aber gut zu wissen, dass man es so machen kann, danke ;)

Aus Performance-Überlegungen wäre es hier (und in den anderen Settern sowie im Konstruktor) besser, den String als const-Referenz zu übergeben. Sonst muss der String möglicherweise zweimal umkopiert werden (einmal beim Aufruf des Setters und ein zweites mal bei der Zuweisung).
</edit>

Als alter Delphianer hätte ich darauf sogar selber kommen müssen :D

Danke an alle für die Hilfe!
 
Zurück