Consider the following example. It consists of two header files, declaring two different namespaces:
// a1.h
#pragma once
#include "a2.h"
namespace a1
{
const int x = 10;
typedef a2::C B;
}
and the second one is
// a2.h
#pragma once
#include "a1.h"
namespace a2 {
class C {
public:
int say() {
return a1::x;
}
};
}
And a single source file, main.cpp:
#include <iostream>
#include "a1.h"
#include "a2.h"
int main()
{
a2::C c;
std::cout << c.say() << std::endl;
}
This way it doesn't compile (tried GCC and MSVC). The error is that a1 namespaces is not declared (C2653 on Windows). If you change include order in main.cpp this way:
#include "a2.h"
#include "a1.h"
you get a symmetric error message, i.e. a2 namespace is not declared.
What's the problem?
You need to use a forward declaration in your header files because you have a circular reference. Something like this:
// a1.h
#pragma once
namespace a2 {
class C;
}
namespace a1
{
const int x = 10;
typedef a2::C B;
}
Just a guess, but your include reference is circular. Meaning the compiler can't figure out which header to compile first. a1 references a2 which references a1.
If possible, merge/reorganize the files so that there is a non-circular chain of includes.
Hope that helps!
When you include a1.h first, it immediately tries to include a2.h before declaring anything
a2.h references something in namespace a1 that hasn't been declared yet
When you include a2.h first, it immediately tries to include a1.h before declaring anything
a1.h references something in namespace a2 that hasn't been declared yet
Removing the typedef from a1.h, which you aren't using, and not including a2.h removes the cycle.
Or as by the other commenter, forward declare class C.
// a1.h
#pragma once
//#include "a2.h"
namespace a1
{
const int x = 10;
// typedef a2::C B;
}
Related
I am trying to define a member struct of a class in a separate file. however, I not sure what is the correct way to implement it.
Below is what I have tried. in code1.cpp is the main source code. I would like to put the definition of the member struct, Mid, to a separate file, code2.cpp. However, in order for code2.cpp know the struct is part of TestCls, I import code1.cpp there and added the guards. I know this is not going to work but I am not sure how to make it work. Thanks
code1.cpp:
#include <iostream>
#include "code2.cpp"
class TestCls {
public:
struct Mid;
};
int main() {
TestCls::Mid mid1;
std::cout << mid1.a << std::endl;
}
code2.cpp
#ifndef XXX
#define XXX
#include <iostream>
#include <sys/dtrace.h>
#include "code1.cpp"
struct TestCls::Mid {
int a = 0;
};
#endif //XXX
Don't include cpp files. Only include header files. While headers files can technically have any (or no) suffix, using source file suffix may end up confusing a build system or compiler to think that it is supposed to be compiled, which you don't want to do with a header. .h or .hpp and few others are commonly used suffixes for headers.
Your code2.cpp includes code1.cpp and code1.cpp includes code2.cpp. Don't have recursive includes like this. While the include guard prevents infinite recursion, this can easily break in some cases.
For a small program like this, as an exercise, I recommend that you first write it entirely into a single file. For example, following would be correct:
class TestCls {
public:
struct Mid;
};
struct TestCls::Mid {
int a = 0;
};
#include <iostream>
int main() {
TestCls::Mid mid1;
std::cout << mid1.a << std::endl;
}
Now, you can slice the file into multiple ones while keeping the order.
// TestCls.hpp
#pragma once
class TestCls {
public:
struct Mid;
};
// TestClsMid.hpp
#pragma once
#include "TestCls.hpp"
struct TestCls::Mid {
int a = 0;
};
// main.cpp
#include "TestCls.hpp"
#include "TestClsMid.hpp"
#include <iostream>
int main() {
TestCls::Mid mid1;
std::cout << mid1.a << std::endl;
}
I used #pragma once for simplicity, buy you can opt for macro guards if you so prefer.
That said, I recommend to reconsider whehter there is any advantage in not defining TestCls::Mid in TestCls.hpp.
Consider this code.
//header.h
int x;
//otherSource.cpp
#include "header.h"
//main.cpp
#include "header.h"
...
int main()
{
}
In this case compiler erred with the message. "fatal error LNK1169: one or more multiply defined symbols found"
but when I add static before x, it compiles without errors.
And here is the second case.
//header.h
class A
{
public:
void f(){}
static int a;
};
int A::a = 0;
/otherSource.cpp
#include "header.h"
//main.cpp
#include "header.h"
...
int main()
{
}
In this case compiler again erred with multiple declaration.
Can anybody explain me the behavior we static variables in classes and in global declarations?? Thanks in advance.
The issue with the static member variable is that you have the definition occur in the header file. If you #include the file in multiple source files, you have multiple definitions of the static member variable.
To fix this, the header file should consist only of this:
#ifndef HEADER_H
#define HEADER_H
// In the header file
class A
{
public:
void f(){}
static int a;
};
#endif
The definition of the static variable a should be in one and only one module. The obvious place for this is in your main.cpp.
#include "header.h"
int A::a = 0; // defined here
int main()
{
}
Declare x as extern in header.h to tell the compiler that x will be defined somewhere else:
extern int x;
Then define x once in the source file which you think is most fitting.
For example in otherSource.cpp:
int x = some_initial_value;
I have written this header file (header1.h):
#ifndef HEADER1_H
#define HEADER1_H
class first ;
//int summ(int a , int b) ;
#endif
and this source files (header1.cpp and main.cpp):
#include <iostream>
#include "header1.h"
using namespace std;
class first
{
public:
int a,b,c;
int sum(int a , int b);
};
int first::sum(int a , int b)
{
return a+b;
}
#include <iostream>
#include "header1.h"
using namespace std;
first one;
int main()
{
int j=one.sum(2,4);
cout << j<< endl;
return 0;
}
But when I run this program in codeblocks , I give this Error :
aggregate 'first one' has incomplete type and cannot be defined .
You can't put the class declaration in the .cpp file. You have to put it in the .h file or else it's not visible to the compiler. When main.cpp is compiled the type "first" is class first;. That's not useful at all because this does not tell anything to the compiler (like what size first is or what operations are valid on this type). Move this chunk:
class first
{
public:
int a,b,c;
int sum(int a , int b);
};
from header1.cpp to header1.h and get rid of class first; in header1.h
You need to declare the whole class in a headerfile (that is included every place the class is actually used). Oterhwise, the compiler won't know how to "find" sum in the class (or how much space it should reserve for the class).
If you're using a main function as well, just define the class at the top and define the main later. It is not necessary to explicitly create a separate header file.
I would like to avoid re-definition from two different include files as follows:
File ABC.h
extern int v=1;
File foo.h
#include "ABC.h"
class Foo
#ifdef BLA
: public ABC
#endif
{
...
};
File bar.h
extern int v=3;
Main:
#define BLA
#include <foo.h>
#include <bar.h>
Basically foo is a class written by me, and bar is a third-party library. But it doesn't seem to work. How should I solve the problem?
Sorry, it's a bit hard to describe, the example is kind of bad as the conflicted parts are actually not variables, but something like #define and wrapped in big blocks of code (error message is: "multiple definition of `__vector_17'"). Is there a way to solve it without using a namespace?
Using a namespace you can solve this problem:
namespace foo
{
int val =1;
}
namespace bar
{
int val =3;
}
using namespace foo;
int x = val; //Now x will be assigned with 1
A namespace is what you need:
namespace foo
{
int v =100;
}
namespace bar
{
int v =500;
}
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..
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__
In each of your header files write:
#ifndef MYHEADERNAME_H
#define MYHEADERNAME_H
code goes here....
#endif
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.