Cannot use struct defined in another class even after using guards - c++

I am trying to use a struct of one class in another class. My first class looks like this:
Class1.h
#ifndef CLASS1_H
#define CLASS1_H
class Class1
{
public:
Class1();
~Class1();
struct St{
int x;
}
St struct1;
private:
};
#endif
Now in the header of the second class, I want to use this struct and variable.
Class2.h
#ifndef CLASS2_H
#define CLASS2_H
#include "Class1.h"
class Class2
{
public:
Class2();
~Class2();
St struct2;
private:
};
However, it says:
identifier "St" is undefined.
When I use it this way:
Class1::St struct1;
the error goes away. What are the issues with my code?

What are the issues with my code?
The issue is St is a nested class. Its fully qualified name is ::Class1::St1. Within the scope of Class2, the unqualified name lookup does not use the scope of Class1, so no declaration of St will be found.
You can fix the issue by doing the following:
When I use it this way:
Class1::St struct1;
the error goes away.

Related

How to deal with codependent classes in c++

I have class1 that needs header of class2.And class2 that needs header of class1 to be included.
I included header of class2 in class1 and header of class1 in class2 and troubles began (in class2 I get error that says that class1 instance do not name a class)
Please can someone explain how to deal with this situation because I googled this question but didn't get what to do
thank you
One often applicable solution to this is to simply forward-declare the classes. For example:
class1.h
#ifndef CLASS1_H
#define CLASS1_H
class Class2;
class Class1 {
public:
// ...
private:
// ...
std::unique_ptr<Class2> owned_child_;
// ...
};
#endif
class2.h
#ifndef CLASS2_H
#define CLASS2_H
class Class1;
class Class2 {
public:
// ...
private:
// ...
const Class1* unowned_parent_;
// ...
};
#endif
Note, however, that this strategy only works so long as you do not write code that requires the definition of the class to be available, which can be achieved when using pointers or references to the class's type. As soon as you use the class type without a reference or pointer, you will need to have available the full declaration of the class already processed and available.

Class static method returning struct containing object of this class

I've got a class:
class SOMECLASS
{
public:
(...)
static SOMESTRUCT GetInfo();
};
And a struct:
struct SOMESTRUCT
{
(...)
SOMECLASS Instance;
};
They are declared in SOMESTRUCT.h and SOMECLASS.h
I'm not able to compile it, even with forward declarations.
I'm still getting:
error: field ‘Instance’ has incomplete type
How can I solve that?
Try the following
SOMECLASS.h
#ifndef SOMECLASS_H
#DEFINE SOMECLASS_H
class SOMECLASS
{
public:
(...)
static struct SOMESTRUCT GetInfo();
};
#endif // SOMECLASS_H
SOMESTRUCT,h
#ifndef SOMESTRUCT_H
#DEFINE SOMESTRUCT_H
#include "SOMECLASS.h"
struct SOMESTRUCT
{
(...)
SOMECLASS Instance;
};
#endif // SOMESTRUCT_H
The answers given above would have been correct if the users include SOMESTRUCT.h.
If the user do this
#include "SOMECLASS.h"
int main()
{
SOMECLASS::GetInfo();
}
The same error would occur.
The reason is the compiler has to know the full definition of the return variable; otherwise it cannot know how to construct it when the function returns.
When SOMECLASS.h is included, the compiler only knows the identifier SOMESTRUCT is a sturct. If the user calls SOMECLASS::GetInfo, the function has to construct a SOMESTRUCT, so the full definition of the struct has to be given before that line in the same file.
To solve it, it is more reasonable to include SOMESTRUCT.h in SOMECLASS.h, so the user can be sure that calling any function in the class would not result in compilation error, as long as they include the header.
One should also forward declare class SOMECLASS in SOMESTRUCT.h.
If there are cases that only SOMESTRUCT.h is used, then the SOMECLASS.h should also be included in SOMESTRUCT.h, because constructing SOMESTRUCT requires the definition of SOMECLASS.h.
You could avoid this is by declaring Instance variable as SOMECLASS& or SOMECLASS* instead of SOMECLASS.
If you really don't want to expose the detailed definition of the SOMESTRUCT, you can try these
define an IInfo interface class with virtual accessor to get information from SOMESTRUCT
use pimpl idiom
By these ways you don't have to include SOMESTRUCT.h in SOMECLASS.h.

error: forward declaration, how to access pointer

I'm doing a small program, just to play with classes.
And I've made two classes, a and b.
I want to be able to access a in b and vice versa.
This is what I got so far:
#ifndef A_HH_
#define A_HH_
#include <string>
class b;
class a
{
private:
string aString;
b* bClass;
public:
a(){aString = "A";}
string getString(){return aString;}
string getBString(){return bClass->bString;}
};
#endif /* A_HH_ */
and b:
#ifndef B_HH_
#define B_HH_
#include <string>
class a;
class b
{
private:
string bString;
a* aClass;
public:
b(){bString = "B";}
string getString(){return bString;}
};
#endif /* B_HH_ */
I want to be able to access the pointer not just store it.
How can I do that?
The problem is that you use the bClass pointer in class a, for that you need the definition of class b. In this case this can be solved by simply including b.hh in a.hh. This simple solution will work as you're only declaring an a pointer (but don't access it) in the class b. A forward declaration is not enough, because it doesn't actually tells the compiler anything more than that the class b exist.
Oh, and you need to change the bClass->bString in a::getBString to bClass->getString(), as b::bString is private. And of course create an actual instance of b and assign it to bClass.
In short, to access members of a struct or a class, you need to meet two conditions:
the accessing element (class, method, ...) must have access "rights" to the referenced member
the definition of the struct/class must be available.
To overcome 1. you can either make the member public, or declare the accessing class or method as friend, or better use a getter method.
To overcome 2., you need to include the header of the referenced class.
You might use templating:
for a:
#ifndef A_HH_
#define A_HH_
#include <string>
#include "b.h"
class a
{
private:
string aString;
b* bClass;
public:
a()
{
aString = "A";
bClass = new b<a>;
}
string getString(){return aString;}
string getBString(){return bClass->getString();}
};
#endif /* A_HH_ */
and for b:
#ifndef B_HH_
#define B_HH_
#include <string>
template <typename T>
class b
{
private:
string bString;
T* aClass;
public:
b()
{
bString = "B";
aClass = new T;
}
string getString(){return bString;}
string getAString(){return aClass->getString();}
};
#endif /* B_HH_ */
This removes the circular dependency

C++ linking 2 classes together how

this maybe a little trivial but I'm puzzled with such problem.
I want to create two classes Class1, Class2. Both classes should contain a field that contains pointer to instance of the other class. So they should be cross linked.
If I do it like this then I get an error from the compiller saying:
- ISO C++ forbids declaration of 'Class1' with no type
- expected ';' before * token
Please help :)
file: class1.h
#ifndef CLASS1_H
#define CLASS1_H
#include "class2.h"
class Class1 {
public:
Class1();
private:
Class2* link;
}
#endif
file: class2.h
#ifndef CLASS2_H
#define CLASS2_H
#include "class1.h"
class Class2 {
public:
Class2();
private:
Class1* link;
}
#endif
Add class declaration (as opposed to definition) before you use it. For example, you could have:
#ifndef CLASS1_H
#define CLASS1_H
class Class2;
class Class1
{
public:
Class1();
private:
Class2* link;
}
#endif
and do the same for Class2.h.
The problem is the circular dependency; each header is trying to include the other, which is impossible.
You don't need the full definition of each class in order to declare a pointer to it; you can replace each #include line with a forward declaration (class Class1; and class Class2;), and then everything should compile happily.

Two classes and inline functions

I have two classes and both of them uses some of the other class, on example:
// class1.h
class Class1;
#include "class2.h"
class Class1 {
public:
static Class2 *C2;
...
};
// class2.h
class Class2;
#include "class1.h"
class Class2 {
public:
static Class1 *C1;
...
};
And when I define it like in example above, it works (I also have some #ifndef to avoid infinite header recurency). But I also want to add some inline functions to my classes. And I read here that I should put definition of inline function in header file, because it won't work if I'll put them in cpp file and want to call them from other cpp file (when I do it I get undefined reference during linking). But the problem here is with something like this:
// class1.h
...
inline void Class1::Foo() {
C2->Bar();
}
I get error: invalid use of incomplete type ‘struct Class2’.
So how can I do it?
You need to delay including the header, but then include it and define your inline methods. By doing this in each header, they are self-sufficient and including one will always include the other, with include guards preventing infinite recursion.
A.hpp
#ifndef INCLUDE_GUARD_B9392DB18D114C1B8DFFF9B6052DBDBD
#define INCLUDE_GUARD_B9392DB18D114C1B8DFFF9B6052DBDBD
struct B;
struct A {
B* p;
void foo();
};
#include "B.hpp"
inline
void A::foo() {
if (p) p->bar();
}
#endif
B.hpp
#ifndef INCLUDE_GUARD_C81A5FEA876A4C6B953D1EB7A88A27C8
#define INCLUDE_GUARD_C81A5FEA876A4C6B953D1EB7A88A27C8
struct A;
struct B {
A* p;
void bar();
};
#include "A.hpp"
inline
void B::bar() {
if (p) p->foo();
}
#endif
You have it mix'd up. What you want is:
// class1.h
class Class2;
class Class1 {
public:
static Class2 *C2;
...
};
// class2.h
class Class1;
class Class2 {
public:
static Class1 *C1;
...
};
And include the respective headers in the source. The line:
class Class1; // or Class2
Declares an incomplete type, and you can have pointers and references to incomplete types. Upon usage, though, it needs to be complete. So just say "hey it'll exist!" in the header, and in the source tell it what it is.
My suggestion is that you place common methods and members into a base class, then derive C1 and C2 from the base class. This may fix the circular dependency issue.