2 Stimmen

Neudefinition der Klasse

Ich habe drei .cpp Dateien und two header files.

Aber wenn ich sie kompiliere, d.h. die Point.cpp, Data.cpp und main.cpp, wird es sagen

Data.h:6:7 redefinition of Data at 'Data.h'
Data.h:6:7 previously definition of 'class Data'

Nachfolgend ist meine Data.h (früher bekannt als 2.h oben)

#include <iostream>
#include <string>

using namespace std;

class Data
{
private:
string sType;
public:
Data();
Data(string);
void setSType(string);
string getSType();
};

Nachfolgend ist meine data.cpp

#include "Data.h"

Data::Data()
{
sType = "";
}

Data::Data(string s)
{
sType = s;
}

void Data::setSType(string ss)
{
sType = ss;
}

string Data::getSType()
{
return sType;
}

Nachfolgend ist meine PointD.h (früher bekannt als 3.h)

#include <iostream>
#include <string>
#include "Data.h"

using namespace std;

class PointD
{
private:
int x
Data data1;
public:
PointD();
PointD(int,Data);

void setX(int);
void setData(Data);

int getX();
Data getData();
};

Nachfolgend ist meine PointD.cpp

#include "PointD.h"

PointD::PointD()
{
x = 0;
}

PointD::PointD(int xOrdinate,Data dd)
{
x = xOrdinate;
data1 = dd;
}

void PointD::setXordinate(int Xordinate)
{
x = Xordinate;
}

void PointD::setData(Data dd)
{
data1 = dd;
};

int PointD::getXordinate()
{
return x;
}

Data PointD::getData()
{
return data1;
}

Dies ist meine main.cpp

#include <iostream>
#include <string>

#include "Data.h"
#include "PointD.h"
using namespace std;

int main()
{
const int MAX_NUM = 20;

Data ldata[MAX_NUM];
PointD pointd[MAX_NUM];

//more codes..
}

Aber wenn ich sie kompiliere, d.h. die Point.cpp, Data.cpp und main.cpp, heißt es

Data.h:6:7 redefinition of Data at 'Data.h'
Data.h:6:7 previously definition of 'class Data'

Kann mir jemand sagen, was hier eigentlich schief gelaufen ist?

5voto

sehe Punkte 346808

Sie müssen Wachen einschließen, oder das einfachste:

 #pragma once

in Ihren Header-Dateien

Voir Zweck der Header-Guards für mehr Hintergrundinformationen

Idee: 1.hpp

#ifndef HEADER_GUARD_H1_HPP__
#define HEADER_GUARD_H1_HPP__

// proceed to declare ClassOne

#endif // HEADER_GUARD_H1_HPP__

1voto

Craig Wright Punkte 1565

Schreiben Sie in jede Ihrer Header-Dateien:

#ifndef MYHEADERNAME_H
#define MYHEADERNAME_H

code goes here....

#endif

1voto

user48956 Punkte 12835

Es ist besser so:

#ifndef DATA_H    /* Added */
#define DATA_H    /* Added */

#include <iostream>
#include <string>

// using namespace std;  /* Removed */

class Data
{
private:
   std::string sType;
public:
   Data();
   Data( std::string const& );          // Prevent copy of string object.
   void setSType( std::string& );       // Prevent copy of string object.
   std::string const& getSType() const; // prevent copy on return
   std::string& getSType();             // prevent copy on return
};

#endif /* DATA_H */

Die große Lösung ist das Hinzufügen von ifndef,define,endif. Die #include-Direktive funktioniert so, als ob man die .h in diese Zeile kopiert und einfügt. In Ihrem Fall sind die include von main.cpp:

   main.cpp
     -> Data.h  (1)
     -> Point.h
        -> Data.h (2)

Bei (2) wurde Data.h bereits in main.cpp bei (1) "eingefügt". Die Klassendeklaration von Data, d.h. "class Data{ .... };" , erscheint zweimal. Dies ist ein Fehler.

Das Hinzufügen von Include-Schutzvorrichtungen am Anfang und am Ende jeder .h-Datei ist gängige Praxis, um dieses Problem zu vermeiden. Denken Sie nicht darüber nach. Tun Sie es einfach.

Eine weitere Änderung, die ich vorschlagen würde, ist die Entfernung aller "using namespace ..."-Zeilen aus jeder .h . Dies macht den Zweck von Namespaces zunichte, der darin besteht, Namen in getrennten Gruppen unterzubringen, damit sie nicht mehrdeutig sind, wenn jemand anderes ein Objekt oder eine Funktion mit demselben Namen haben will. Dies ist kein Fehler in Ihrem Programm, sondern ein Fehler, der nur darauf wartet, zu passieren.

Zum Beispiel, wenn wir haben:

xstring.h:

namespace xnames
{
    class string
    {
        ...
    };
}

Foo.h

#include <xstring>
using namespace xnames;
...

test.cxx:

#include "Foo.h"  
#include "Data.h"    // Breaks at:   Data( string );  -- std::string or xnames::string?

...
void test()
{
   string x;  // Breaks.  // std::string or xnames::string?
}

Hier weiß der Compiler nicht mehr, ob Sie xnames::string oder std::string meinen. Dies schlägt in test.cxx fehl, was durch eine genauere Formulierung behoben werden kann:

void test()
{
   std::string x;
}

Wenn Sie also jemandem diese Header-Datei zur Verfügung stellen, wird es Fälle geben, in denen sie mit dessen Code inkompatibel ist und nur durch Ändern Ihrer Header-Dateien und Entfernen der "using namespace ...;"-Zeilen behoben werden kann.

Auch hier handelt es sich um einen guten Kodierungsstil. Denken Sie nicht darüber nach. Tun Sie es einfach.

Außerdem habe ich in meiner Version von Data.h die Methodenparameter und Rückgabetypen so geändert, dass sie Referenzen sind (mit dem &). Dadurch wird verhindert, dass das Objekt und sein gesamter Zustand kopiert werden. Einige Klugscheißer werden darauf hinweisen, dass die is-Implementierung der String-Klasse dies durch Copy-on-Write verhindert. Vielleicht ist das so, aber im Allgemeinen sollten Sie Referenzen verwenden, wenn Sie Objekte übergeben oder zurückgeben. Das ist einfach der bessere Programmierstil. Machen Sie es sich zur Gewohnheit.

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