Why can't I do something like this in C++?
A.h:
#ifndef A_H
#define A_H
#include "B.h"
struct A {
int a;
};
void doStuff1 (B b); // Error here
#endif
B.h:
#ifndef B_H
#define B_H
#include "A.h"
struct B {
int b;
};
void doStuff2 (A a); // Error here
#endif
I get an error that 'A' was not declared in this scope and the same with 'B'.
I know about forward declaration, but I wanted to see if it was possible to have a set up like this as pass-by-value instead of by reference/pointer. Why does the compiler behave like this, if both A and B are in fact declared by the time the compiler reaches that code?
The basic lesson: Includes are processed before any C++ is parsed. They're handled by the pre-compiler.
Let's say that A.h winds up being included prior to B.h. You get something like this:
#ifndef A_H
#define A_H
// ----- B.h include -----
#ifndef B_H
#define B_H
#include "A.h" // A_H is defined, so this does nothing
struct B {
int b;
};
void doStuff2 (A a); // Error here
#endif
// ----- B.h include -----
struct A {
int a;
};
void doStuff1 (B b); // Error here
#endif
At this point, the C++ compiler can take over and start parsing things out. It will try to figure out what the parameter to doStuff2 is, but A hasn't been defined yet. The same logic holds true going the other way. In both cases, you have dependencies on types that haven't been defined yet.
All of this just means that you have your dependencies out of order. It isn't a problem with pass-by-value. Your types must be defined prior to your methods. That's all - see the example below.
// Example program
#include <iostream>
#include <string>
// data_types.h
struct A
{
int x;
};
struct B
{
int y;
};
using namespace std;
// methods_A.h
void foo(A a)
{
a.x = 3;
cout << "a: " << a.x << endl;
}
// methods_B.h
void bar(B b)
{
b.y = 4;
cout << "b: " << b.y << endl;
}
int main()
{
A first;
B second;
first.x = 0;
second.y = 100;
foo(first);
bar(second);
cout << "A: " << first.x << ", B: " << second.y << endl;
}
Example output
a: 3
b: 4
A: 0, B: 100
You have a circular include. You need to either separate them into different header files, such as having A.h and B.h only declare the struct/classes and having a different header file declare the functions.
The problem can also be solved by using forward declarations and passing by reference instead:
struct A;
struct B;
void doStuff1(A& a);
void doStuff2(B& b);
Related
I have this situation where I'm trying to pass a map after I populated it, from a file to a class:
A.h - a normal header file where I have a function prototype and a map
#include <unordered_map>
func1();
static std::unordered_map<glm::ivec3, Chunk*, KeyHasher> chunks;
A.cpp
#include "A.h"
func1() {
// ...
chunks.insert(pair<glm::ivec3, Chunk*>(pos, chunk));
cout << chunks.size(); // here I have the right size
// ...
}
B.h
#include "A.h"
class B {
public:
my_func();
}
B.cpp
B::my_func() {
// ...
cout << chunks.size(); // size is 0
for (auto& c : chunks) {
// ... do something
}
}
My question is, why in B.cpp chunks map arrives empty? I thought that if I use static this will solve my problem. Thank you for your time!
You are declaring the chunks variable as static in A.h. That is the problem.
Every .cpp that #include's A.h will get its own copy of the chunks variable. That is why chunks is populated in A.cpp but is empty in B.cpp.
If you want to share the chunks variable across translation units, it needs to be declared as extern instead of static, and then defined in one of .cpp files, eg:
A.h
#include <unordered_map>
func1();
extern std::unordered_map<glm::ivec3, Chunk*, KeyHasher> chunks;
A.cpp
#include "A.h"
std::unordered_map<glm::ivec3, Chunk*, KeyHasher> chunks;
func1() {
// ...
chunks.insert(pair<glm::ivec3, Chunk*>(pos, chunk));
cout << chunks.size(); // here I have the right size
// ...
}
B.h
class B {
public:
my_func();
};
B.cpp
#include "B.h"
#include "A.h"
B::my_func() {
// ...
cout << chunks.size(); // here I have the right size
for (auto& c : chunks) {
// ... do something
}
}
I have a simple for loop (though it is not the only component within the method) that is compiled with GNU 4.8.1.10 compiler with debugging option is off and optimization levels O-0, O-2 and O-3 distinctively. The loop is as below:
const int iMyConst = 10; // defined in another header
void myFunc(uint8_t ui8InputNum)
{
// some stuff
for(int i=static_cast<int>(ui8InputNum); i<iMyConst; i++)
{ // loop content
}
}
What happens is that, when I call myFunc(10) (equal to iMyConst), the for loop is executed. This is not the expected behaviour. Inside the loop I printed the variable values as well. They are printed as expected but with an exception: i<iMyConst came out to be true where i was printed as 10. Moreover, I forced all process to run on single core, the unexpected behaviour happened again.
I ran the code in debug mode, and saw that the loop is not executed as expected. Then I defined the loop variable as volatile int i, this time the loop is not executed as well.
The problem might sound odd but it is all what happened. What is the cause of this problem? The system is 64-bit and has 12 cores.
// main.cpp
//============================================================================
// Name : loopProblem.cpp
//============================================================================
#include "a.h"
#include "b.h"
#include <iostream>
int main() {
a* myA = new a;
b* myB = new b;
myB->itsA = myA;
myB->dummyFunc();
delete myA;
delete myB;
return 0;
}
// a.h
#ifndef A_H_
#define A_H_
#include <stdint.h>
// #include <cstdint> not available in c++03
class a
{
public:
a();
~a();
void myFunc(uint8_t ui8InputNum);
};
#endif /* A_H_ */
// a.cpp
#include "a.h"
#include "c.h"
#include <cstdio>
a::a()
{
}
a::~a()
{
}
void a::myFunc(uint8_t ui8InputNum)
{
// some stuff
for(int i=static_cast<int>(ui8InputNum); i<iMyConst; i++)
{
printf("i: %d, comp: %d\n", i, (i<iMyConst));
}
}
// b.h
#ifndef B_H_
#define B_H_
class a;
class b {
public:
b();
~b();
a* itsA;
void dummyFunc();
};
#endif /* B_H_ */
// b.cpp
#include "b.h"
#include "a.h"
#include <cstddef>
b::b() : itsA(NULL)
{
}
b::~b()
{
}
void b::dummyFunc() {
itsA->myFunc(10);
}
// c.h
#ifndef C_H_
#define C_H_
const int iMyConst = 10;
#endif /* C_H_ */
I'm trying to declare a class object as extern but am getting the below error:
g++ a1.cpp -std=c++11
In file included from b1.h:5:0,
from a1.cpp:2:
c1.h:6:8: error: ‘b1’ does not name a type
extern b1 obj_b1;
^
I have looked in
Issue declaring extern class object
and
'[Class name]' does not name a type in C++
and I THINK I am following the steps mentioned there. But couldn't find what's the issue.
Files are :
a1.cpp
#include<iostream>
#include "b1.h"
b1 obj_b1;
int main(){
//access object from class B
std::cout << " test " << std::endl;
std::cout << " obj_b1 value is " << obj_b1.value << std::endl;
obj_b1.value = 6;
return 0;
}
b1.h
#ifndef CLASS_B1
#define CLASS_B1
#include "c1.h"
class b1{
public:
int value=5;
int print_value();
};
#endif
b1.cpp
#include <iostream>
#include "b1.h"
int b1::print_value(){
std::cout << "value in b1 is " << value << std::endl;
}
c1.h
#ifndef CLASS_C1
#define CLASS_C1
#include "b1.h" // this is an attempt to fix issue, but didnt work
extern b1 obj_b1; // Is there a better place to declare this ?
class c1 {
private:
int c1_value=10;
int c1_print_value();
};
#endif
c1.cpp
#include<iostream>
#include "c1.h"
int c1::c1_print_value()
{
std::cout << "in c1 , value is " << c1_value << std::endl;
std::cout << " obj_b1.value is " << obj_b1.value << std::endl;
return 0;
}
I can not understand why the compiler complains about b1, when I have added b1.h just above the extern declaration. Can someone help to solve the issue ?
b1.h includes c1.h, and c1.h includes b1.h. This is is a mess. By using the #indef/#define combo, you have prevented an infinite recursion, but it is still a mess.
obj_b1 doesn't have anything to do with class c1, so remove extern b1 obj_b1; from c1.h.
Now c1.h doesn't depend on anything in b1.h, so you can remove #include "b1.h" from c1.h.
An for similar reason, you should remove #include "c2.h" from b1.h.
On the other hand c2.cpp does depend on obj_b1 (assuming obj1.name is a typo, and should be obj_b1.name), so you should put extern b1 obj_b1; in b1.h and #include "b1.h" in c2.cpp.
For some extra cleanup, move b1 obj_b1; from a1.cpp to b1.cpp
Sorry for the noob question..
devf.h
#ifndef DEVF_H
#define DEVF_H
#include <string>
struct A {
int ax();
std::string ay(std::string jj);
};
struct B {
struct A* f;
int bx() {
return f->ax();
}
std::string by(std::string jj){
return f->ay(jj);
}
};
#endif // DEVF_H
devf.cpp
#include "devf.h"
int A::ax() {
return 5;
}
std::string A::ay(std::string jj){
return jj;
}
I get this error:
multiple definition of `A::ax()'
multiple definition of `A::ay(std::string)'
How can I solve this problem? I want the definitions of ax and ay functions in header file and the implementions in .cpp
Try doing this with your code:
devf.h
#ifndef DEVF_H // Add this line
#define DEVF_H // Add this line
// #include <iostream> // removed this as not needed from what is shown
#include <string> // added this as is needed
struct A {
int ax() const; // added const as it doesn't change
std::string ay( const std::string& jj ) const; // changed string to const ref & added const
};
struct B {
/*struct*/ A* f; // keyword struct not needed here.
int bx() const { // added const
return f->ax();
}
std::string by( const std::string& jj ) const { // changed to const ref & added const
return f->ay( jj );
}
};
#endif // !DEVF_H // Add this line
devf.cpp
#include "devf.h"
int A::ax() const {
return 5;
}
std::string A::ay( const std::string& jj ) const {
return jj;
}
Then you asked this or made this statement:
How can I solve this problem? I want the definitions of ax and ay functions in header file and the implementions in .cpp
devf.h
#ifndef DEVF_H
#define DEVF_H
#include <string>
struct A {
int ax() const;
std::string ay( const std::string& jj ) const;
};
struct B {
A* f;
int bx() const;
std::string by( const std::string& jj ) const;
};
#endif // !DEVF_H
devf.cpp
#include "devf.h"
int A::ax() const {
return 5;
}
std::string A::ay( const std::string& jj ) const {
return jj;
}
int B::bx() const {
return f->ax();
}
std::string B::by( const std::string& ) const {
return f->ay( jj );
}
This should help from what you have shown.
I've tried it with this:
main.cpp
#include <iostream>
#include "devf.h"
int main() {
B b;
std::cout << b.bx() << std::endl;
std::cout << b.by( "hello world" ) << std::endl;
std::cout << "\nPress any key and enter to quit." << std::endl;
char q;
std::cin >> q;
return 0;
}
output
5
hello world
Press any key and enter to quit.
- EDIT
I asked the OP: Are you including other header files?
The OP answered with:
Yes, the header "devf.h" is included in other headers
And I believe this is where the OP's problem resides. I believe that the OP is a victim of Circular Includes which will result in multiple definitions.
Example:
A.h
#ifndef A_H
#define A_H
#include "B.h" // circular include
struct A {
int a;
B b;
};
#endif // !A_H
B.h
#ifndef B_H
#define B_H
#include "A.h" // circular include
struct B {
int b;
};
#endif // !B_H
To resolve this circular include problem...
You need to use class or struct prototypes - forward declarations in the headers; works with pointer & reference types.
Only include other header files within a header file if the definition not the declaration is needed.
Once you have the class or struct's forward declaration in the header file
remove that class's include directive and put it within its cpp file
fixing the above example:
A.h
#ifndef A_H
#define A_H
// Since A has a pointer to B we remove the include from here
// and replace it with a forward declaration or class prototype...
// #include "b.h" // cicular include
class B;
struct A {
int a;
B b;
};
#endif // !A_H
A.cpp
#include "A.h"
#include "B.h" // moved the include to here - prevents circular includes
B.h
#ifndef B_H
#define B_H
// Since B does not require A we can omit this all together.
//#include "A.h" // circular include
struct B {
int b;
};
#endif // !B_H
B.cpp
#include "B.h"
You can refer to this Q & A Resolve build errors due to circular dependency amongst classes on stack for a more detailed explanation.
Once you go through the rest of your code base and fix all of the circular includes you should have no error as the above set of classes do compile and run without error.
I am getting those 2 errors :
-error: expected identifier before numeric constant
-error: expected ',' or '...' before numeric constant
I try from the second class to have an object to first class with parameters and it gives me those 2 errors. Without parameters works fine.
This is main:
#include<iostream>
#include "c1.h"
#include "c1.cpp"
#include "c2.h"
#include "c2.cpp"
using namespace std;
int main()
{
c2 obj2();
return 0;
}
This is first class header:
#ifndef C1_H
#define C1_H
class c1
{
public:
c1(int,int);
};
#endif // C1_H
And its cpp file:
#include "c1.h"
c1::c1(int x,int y)
{
std::cout << "\nCtor c1\n" << x << "\n" << y << "\n";
}
And the second file header:
#include "c1.h"
#ifndef C2_H
#define C2_H
class c2
{
public:
c2();
c1 obj1(10,2);
};
#endif // C2_H
And its cpp:
#include "c2.h"
c2::c2()
{
std::cout << "\nCtor c2\n";
}
Thank's.
Don't use CPP files in includes.
For solution to this problem, you can change the object to pointer and use something like c1* obj1=new c1(10,2) and it should work.
A better way of doing this is, add a class member c1* obj1; and use constructor of c2 to really create the c1 object obj1=new c1();