3 Stimmen

Sollten Sie sich auf einen anderen Header für die darin enthaltenen Header verlassen?

Unter der Annahme, dass alle Header geschützt sind, könnte man sagen, dass Sie einen abstrakten Datentyp haben.

#include "that.h"
#include "there.h"

class Foo {
 protected:
  // Functions that do stuff with varOne and varTwo
 private:
  that varOne; 
  there varTwo;
 ...
};

Würden Sie sich dann in den Klassen, die von foo erben (und somit foo.h einschließen), auch die Mühe machen, das und das einzuschließen? Normalerweise schließe ich alles ein, was eine Klasse braucht, unabhängig davon, ob sie es bereits von einem anderen Include erhält. Ist das überflüssig?

3voto

Crashworks Punkte 39230

Die redundante Einbindung von Header-Dateien, die sonst direkt eingebunden worden wären, hat einen Nachteil: Sie zwingt den Compiler, sie erneut zu öffnen und zu reparieren. Zum Beispiel, in

a.h:

#ifndef __A_H
#define __A_H
// whatever
#endif

b.h:

#ifndef __B_H
#define __B_H
#include "a.h"
// whatever
#endif

c.cpp:

#include "a.h"
#include "b.h"
//whatever

a.h muss zweimal geöffnet und gelesen werden -- obwohl die #ifndef bewirkt, dass der Preproc den Inhalt von a.h bei der zweiten Einbindung ignoriert, muss er dennoch zumindest die Datei von der Festplatte laden und ihre Bytes aus dem #ifndef a la #endif .

Dies kann die Kompilierung verlangsamen. Es wird nicht brechen Ihr Build oder etwas aber, es wird nur ein Ärgernis in wirklich großen Projekten, wo Kompilierungen können viele Minuten dauern.

Wenn Sie #pragma once in Ihren Headern, besteht eine gute Chance, dass ein aufmerksamer Compiler die Dateinamen auf einer höheren Ebene zwischenspeichert und den zweiten Einschluss von a.h ganz ignoriert. Auch das kann die Builds beschleunigen.

1voto

Don Neufeld Punkte 21948

Meiner Erfahrung nach ist es besser, dies und das in Foo.h weiterzudeklarieren, anstatt sie überhaupt einzuschließen, da sie technisch nicht benötigt werden, da sie per Referenz übergeben werden.

In diesem Fall würde Foo.h wie folgt aussehen:

class that;
class there;

class Foo
{
    public:

        void func( that &param ) = 0;
        void funcTwo( there &param ) = 0;
        ...
};

1voto

Das Problem ist, dass Sie auf diese Weise zusätzliche Dinge in Ihre Obj-Dateien einfügen. Die Header-Guards verhindern dies nicht. Alles, was Sie referenzieren, muss in Ihrem Objekt enthalten sein, also haben Sie nicht einfach viele Header, die andere Header enthalten, und fügen diese dann an anderer Stelle ein. Wenn Sie mit Ihren Headern schlampig umgehen und viele Dateien haben, wird der Code schnell aufgebläht und die Kompilierzeit verlangsamt.

0voto

Peter Alexander Punkte 51742

Es liegt wirklich an Ihnen. Wenn es klar ersichtlich ist, dass die Superklasse sie eingebunden hat (d.h. ohne einen Blick auf den Header zu werfen), dann wäre es sinnvoll, die #include . Natürlich können Sie sie sicherheitshalber hinzufügen.

0voto

Charles Ma Punkte 44109

Es ist nicht unbedingt überflüssig. Die Tatsache, dass Sie getrennte Header-Dateien und Quelldateien haben, bedeutet, dass Sie src- und Header-Dateien austauschen können, solange die Quelldateien Definitionen für die Header-Dateien liefern.

Die .h-Datei sollte nur Dinge enthalten, die im Header verwendet werden. Sie braucht zum Beispiel stdio nicht, wenn es keine io-Deklarationen im Header gibt, stattdessen sollte sie nur in die src-Datei aufgenommen werden, wenn sie zum Beispiel printf verwendet.

Es kann jedoch Situationen geben, in denen ein Header, den Sie verwenden können, ein bestimmtes Include benötigt, während ein anderer Header nicht benötigt wird (z.B. wenn ein Header eine restriktivere Schnittstelle ist als der andere). In diesem Fall ist es besser, die .h-Includes zu duplizieren.

Da es geschützt ist, macht es wirklich keinen Unterschied zu dem endgültigen Objekt/der endgültigen Exe, die Sie produzieren, und es erhöht die Kompilierzeit um nichts, worüber man sich Gedanken machen sollte. Es ist also besser, sie einzuschließen, nur für den Fall, dass Sie irgendwann eine andere .h-Datei verwenden wollen.

edit: konkreteres Beispiel inc1.h

#ifndef INC1_H
#define INC1_H
inc1_struct {                                                            
   int x;
};
#endif

inc2.h

#ifndef INC2_H
#define INC2_H
#include "inc1.h"
void inc2_f();
struct inc1_struct *inc2_callinc1();
#endif 

prog.cpp #include "inc1.h" #include "inc2.h"

include #include

void inc2_f() {
   printf("inc2_f\n");
}

struct inc1_struct *inc2_callinc1() {
   return (struct inc1_struct*) malloc(sizeof(struct inc1_struct));
}

int main(int argc, char **argv) {
   struct inc1_struct *s = inc2_callinc1();
   return 0;
}

Dies würde kompilieren, aber sagen wir mal, Sie wollen nicht die

struct inc1_struct *inc2_callinc1();

in inc2.h

Dann brauchen Sie inc1.h nicht in die Datei inc2.h einzubinden, aber wenn Sie nicht auch die Definition von inc2_callinc1() in prog.cpp löschen wollen, dann müssen Sie inc1.h einbinden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X