2

I got three .cpp files and two header files.

But when i compile them, meaning the Point.cpp, Data.cpp and main.cpp, it will say

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

Below is my Data.h(previously known as 2.h at above)

#include <iostream>
#include <string>

using namespace std;

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

Below is my 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;
}

Below is my PointD.h (previously known as 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();
};

Below is my 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;
}

This is my 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..
}

But when i compile them, meaning the Point.cpp, Data.cpp and main.cpp, it will say

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

Can anybody let me know whats actually went wrong here..

baoky chen
  • 799
  • 2
  • 11
  • 20

3 Answers3

5

You need to use include guards, or the easiest:

 #pragma once

in your header files

See Purpose of Header guards for more background

Idea: 1.hpp

#ifndef HEADER_GUARD_H1_HPP__
#define HEADER_GUARD_H1_HPP__

// proceed to declare ClassOne

#endif // HEADER_GUARD_H1_HPP__
Community
  • 1
  • 1
sehe
  • 374,641
  • 47
  • 450
  • 633
  • 4
    `#pragma once` - there's no excuse to use a compiler-specific solution to this problem (and unless you're deriving it from the specific error message, you have no idea if his compiler even supports this). – mah Oct 08 '12 at 17:09
  • @baokychen: `#ifndef MY_HEADER_H #define MY_HEADER_H ... #endif` (obviously broken up over multiple lines. Your code replaces the `...`) – Ed S. Oct 08 '12 at 17:12
  • @baokychen: Most compilers support `#pragma once`. But I linked to the more verbose solution. Edited to show the gist of that, too :) – sehe Oct 08 '12 at 17:13
  • 1
    Darn. Friendly SO crowd today: Everyone is too lazy to type a proper answer, but if I type a short and helpful answer, linking to a longer answer, I get downvotes. Go figure ? – sehe Oct 08 '12 at 17:14
  • 1
    Even with _most_ compilers supporting it, it's nonstandard. It's one thing for someone that already knows what they're doing to use the pragma, but it's entirely different to suggest it to someone that doesn't understand the basics. Regarding the downvotes -- I commented without voting, and after you added the #ifdef I actually upvoted you. – mah Oct 08 '12 at 17:17
  • @mah Thanks for that. I'll try to be more complete next time around, time permitting – sehe Oct 08 '12 at 17:20
1

In each of your header files write:

#ifndef MYHEADERNAME_H
#define MYHEADERNAME_H

code goes here....

#endif
Craig Wright
  • 1,575
  • 1
  • 11
  • 19
  • @baoky chen if you're getting the same issue then you're not applying the guard correctly. The value you define must be the same value you are checking for and it must be unique for each header (thus the suggestion to name it based on the header file name). – mah Oct 08 '12 at 17:19
  • Each header has to have it's own macro guard. For "header1.h" use HEADER1_H. For "header2.h" use "HEADER2_H". Lots of other naming conventions are possible but you'll want one that has a high probability of ensuring uniqueness. – Craig Wright Oct 08 '12 at 17:19
1

Its better like this:

#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 */

The big fix is adding ifndef,define,endif. The #include directive works as if copying and pasting the .h to that line. In your case the include from main.cpp are:

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

At (2), Data.h has already been `pasted' into main.cpp at (1). The class declaration of Data, i.e. "class Data{ .... };" , appears twice. This is an error.

Adding include guards to the top and bottom of every .h are standard practice to avoid this problem. Don't think about it. Just do it.

Another change I'd suggest is to remove any "using namespace ..." lines from any .h . This breaks the purpose of namespaces, which is to place names into separate groups so that they are not ambiguous in cases where someone else wants an object or function with the same name. This is not an error in your program, but is an error waiting to happen.

For example, if we have:

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?
}

Here the compiler no longer knows whether you mean xnames::string or std::string. This fails in test.cxx, which is fixable by being more specific:

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

However, this compilation still now breaks in Data.h. Therefore, if you provide that header file to someone, there will be cases when it is incompatible with their code and only fixable by changing your header files and removing the "using namespace ...;" lines.

Again, this is just good coding style. Don't think about it. Just do it.

Also, in my version of Data.h, I've changed the method parameters and return types to be references (with the &). This prevents the object and all of its state from being copied. Some clever-clogs will point our that the string class's is implementation prevents this by being copy-on-write. Maybe so, but in general, use references when passing or returning objects. It just better coding style. Get in the habit of doing it.

user48956
  • 14,850
  • 19
  • 93
  • 154