Frage von Felix193, 30

[C++] Kennt ihr gute Tutorials zu den Headern oder könnt ihr mir das erklären (file.h)?

Hallo,

ich bin momentan dran, C++ zulernen. Die Syntax zu benutzen, fällt mir nicht schwer, da ich bereits schon Erfahrung mit Java hab.

Leider habe ich noch Probleme mit den Header Files (file.h) für weitere Klassen. Wann genau muss man diese benutzen? Meines Wissens nach muss man diese nur benutzen, wenn man eine Weitere Klasse erstellen will. Dann frage ich mich, was dort reingehört. Ich weiß bereits, dass es ein Grundgerüst gibt und dass ich für jede Methode folgendes Eintragen muss:

methode(varX, varY);

Ist das alles? Könnt ihr mir ein Tutorial empfehlen oder mir das erklären? Vielen Dank!

Antwort
von reddox86, 8

Eigentlich ganz einfach erklärt. Bei Java hast du einen Compiler der jede .java in eine .class umwandelt. Die JVM führt dann die .class aus und sieht: Hier muss noch eine Rechner.class geben mit der Funktion

int Addiere(int, int)

sollte dass nicht der Fall sein, gibt es entwerder eine MethodNotFoundException oder ClassNotFoundException. Das vereinfacht den Kompilierungsvorgang ungemein, hat aber den Nachteil das eventuelle Fehler sehr spät auftreten (wenn die Klasse oder Funktion nur sehr selten aufgerufen wird).

C++ baut hier aber eine Exe, die für sich alleine laufbar ist (abgesehen von dynamischen Bibliotheken, die lasse ich hier mal ausser Acht ist auch eine andere Baustelle).

HIer gibt es keine JVM, das macht alles das Programm selber, also muss da die Info schon vorher da sein.

Du hast also nun ein kleines Programm:

// Datei: main.cpp

#include <iostream>

int main()
{
  Rechner rechner;
std::cout << rechner.Addiere(1, 2;
return 0;
}

Problem ist nun: woher weiß der Compiler was die Klasse Rechner ist.

Das kannst du theoretisch machen wie bei Java:

class Rechner
{
public:
  int Addiere(int a, int b)
  {
    return a + b;
  }
};

Aber, die Info muss in der gleichen Datei sein. Also so:

// Datei: main.cpp

#include <iostream>

class Rechner
{
public:
int Addiere(int a, int b)
{
return a + b;
}
};

int main()
{
Rechner rechner;
std::cout << rechner.Addiere(1, 2);
return 0;
}

Funktioniert so ganz gut, hat aber 2 Nachteile: Wenn du die Klasse wiederverwenden willst musst du das jedes mal in die neue Datei kopieren, was ja auch nicht so gut ist. Und: Das Programm wird sehr schnell sehr unübersichtlich.

Also stattdessen kannst du den Code vom Rechner in eine Header Datei packen, das würde dann so aussehen:

// Datei: Rechner.h

#ifndef _RECHNER_H_
#define _RECHNER_H_

class Rechner
{
public:
  int Addiere(int a, int b)
  {
    return a + b;
  }
};

#endif //_RECHNER_H_
// Datei: main.cpp

#include <iostream>
#include "Rechner.h"

int main()
{
Rechner rechner;
std::cout << rechner.Addiere(1, 2);
return 0;
}

Damit hättest du schon alles in eine Header Datei gepackt und wärst theoretisch auf der guten Seite.

Bevor ich weitermache ein paar Takte zu den Zeilen mit _RECHNER_H_: Das ist ein so genannter Includeguard. Damit verhinderst du, dass ein Header ausversehen 2 mal inkludiert wird (das mag der Compiler nicht, wenn eine Klasse oder Funktion 2 mal definiert wird). Was ein #include nämlich macht ist wesentlich das ersetzen vom #include "XYZ" mit dem Inhalt von der Datei XYZ, wenn du jetzt aber noch einen 2. Header inkludierst, der auch auf Rechner.h verweist, bekommst du ein Problem (und das kann man in der Regel auch nicht überblicken). Deswegen bieten die meisten Compiler auch einen Automatismus an, dass du mittels

#pragma once

am Anfang der Datei sicherstellst (bzw der Preprozessor sicherstellt) dass die Datei nicht 2 mal inkludiert wird (also anstelle der ifdef, define und endif). Hat den Vorteil: Du musst nicht sicherstellen, dass der Name von dem define einzigartig in deinem Projekt ist (Header kopieren ist da eine gern gesehene Fehlerquelle, wenn man vergisst das anzupassen nach dem umbenennen). Nachteil: Es ist nicht Teil vom Standard (mir fällt aber kein Compiler ein, der es nicht unterstützt) und es gibt ganz spezielle Fälle wo das nicht funktioniert (Mischmasch aus UNC-Pfaden und lokalen Pfaden im Projektgefüge). Deswegen wird in großen Projekten gerne mal auf das #pragma once verzichtet.

Was nun aber noch zum perfekten Header fehlt: Kein Code im Header. An der Stelle ist es eigentlich egal...aber so eine Klasse kann auch mal gerne komplexer sein (deswegen extrahiert man sie ja). Wenn die jetzt von mehreren C++ files genutzt wird, wird es für den Compiler (und den ungeduldigen Programmierer) unangenehm, denn wie schon gesagt: Der Inhalt vom Header wird vor dem kompilieren in die Datei kopiert (und müsste dementsprechend mehrmals kompiliert werden.

Deswegen, um die Sache rundzumachen, den Code in eine cpp auszulagern:

// Datei: Rechner.h

#ifndef _RECHNER_H_
#define _RECHNER_H_

class Rechner
{
public:
  int Addiere(int a, int b);
};

#endif //_RECHNER_H_
// Datei: Rechner.cpp

#nclude "Rechner.h"

int Rechner::Addiere(int a, int b)
{
  return a + b;
}

Gut, ist nun doch etwas ausführlicher geworden, zum Abschluss noch einen kurzen Exkurs zu <> vs "" in dem #include: Das beschreibt wo du die Header Dateien suchst. Bei <> wird in den System Include Pfaden (bzw. das was mit /I bzw -I angegeben ist) gesucht, bei "" erst im lokalen Pfad, dann in den <> Pfaden gesucht. Du kannst theoretisch immer "" nutzen, aber wenn man das trennt, kann man sehr schön im Code dokumentieren, was eigener und was fremder Code ist.

Antwort
von LeonardM, 19

Eigentlich wird für jede cpp datei auch ne h datei verwendet. Bsp: void a(string b); kommt in die h datei und in die cpp datei kommt void a(string b){/*code*/}

Antwort
von RakonDark, 12

Hier wird es gut erklärt

http://www.willemer.de/informatik/cpp/aufteil.htm

Keine passende Antwort gefunden?

Fragen Sie die Community

Weitere Fragen mit Antworten