Each of the following statements have include guards around them, for their corresponding header files.
C extends B, things subclass B so they can get a pointer to A– but A has several fields that are subclasses of B.
My current solution is to store Bs in a void array, and use template methods you return the correct object based on run-time type information. But I want to know if there is a way for A to have C fields, even if C needs to link back to A, Ahead Of Time(Compile time).
I have taken a few courses on object oriented programming(they were mostly in java), but none that focused specifically on C++.
This is probably a common problem, and this question has probably already been asked and answered here– but I don't know what keywords to use to find such a solution.
A.h
//#include "C.h" //would cause cyclical include
class A {
public:
A();
virtual ~A();
/**Type must be checked at runtime, because otherwise cyclical includes occur*/
template <class T> T* getComponent();
private:
//C* aComponent; //desired implementation
//Current implementation
void* components;
unsigned char componentCount;
};
B.h
#include "A.h"
class B {
public:
B();
virtual ~B();
A* getRoot();
private:
A* aRoot;
};
C.h
#include "B.h"
class C : B {
public:
B();
virtual ~B();
};
Other OOP languages I've used just resolve such problems behind the scenes, where as C++ requires that the build order be correct. I saw several answers to other questions that looked vaguely similar to this one, but they were kind of unclear, please be concise about your answer.
Just use forward declarations:
class C;
Putting that at the top of A.h will allow you to use the class as the type, instead of using void pointers.
EDIT: To clarify, this simply signals to the compiler that there's some class called C, but there's no definition for it. You will be able to declare pointers to it, but you will not be able to use any of its members until the compiler sees the actual definition for it (which shouldn't be a problem).
Related
All the solutions to circular include dependencies I've seen just say in "this particular case" the full class definition isn't necessary since "you" are only using pointers to that class.
I encountered this problem and fixed it using forward declarations.
I am wondering what are you supposed to do when you need the specific definition of the other class in both classes.
Also, why does using a pointer to the class allow you use a forward declaration instead of a class definition?
In what cases would you need the specification known beforehand for both classes?
One impossible case is the following:
class A
{
B m_b;
};
class B
{
A m_a;
};
But this is impossible since the size of class A depends on the size of class B, but the size of class B depends on the size of class A. You'll also get an infinite series A myA; myA.m_b.m_a.m_b.m_a.... when you try to construct either.
If you use pointers, you don't need to know the size of either; a pointer is always the same size depending on the platform your are on. And the series disappears because objects in the heap need to be created explicitly.
I am wondering what are you supposed to do when you need the specific
definition of the other class in both classes.
It can be done with forward declarations and deferred definitions in modern compilers. Many older compilers only allow pointers & references to forward declared types.
Here's a contrived example:
A.hpp
class B;
class A
{
public:
int32_t Value;
A(int32_t value) : Value(value) { }
int32_t Add(B b) const;
}
B.hpp
#include "A.hpp"
class B
{
public:
int32_t Value;
B(int32_t value) : Value(value) { }
int32_t Sub(A a) const;
}
AB.hpp
#include "A.hpp"
#include "B.hpp"
inline int32_t A::Add(B b) const
{
return this->Value + b.Value;
}
inline int32_t B::Sub(A a) const
{
return this->Value - a.Value;
}
Also, why does using a pointer to the class allow you use a forward
declaration instead of a class definition?
Forward declarations are just names to the compiler. The concept exists so you can use types that haven't been defined yet. This is necessary because of the way C++ parses code, an artifact of the C language it inherits a great deal from. C++ parsers are really just forward-only text processors that inject text when you #include and use macros. It's a conceptually simple model that made C/C++ compilers easier to write in the early days. Contrast this to C#/Java where you just use using/import and happily create circular dependencies between classes with simple syntax.
Pointers are really just integers, similar to short and int, but with special semantics enforced by the language and a fixed size known at compile time based on the CPU architecture. This makes pointer declarations very simple for compilers to deal with.
Forward declaration facilitates circular dependencies and implementation hiding(which also happens to speed up compilation time). Consider the pimpl idiom. Without forward declarations there's no type-safe way to hide implementation details.
I got this syntax I don't really understand:
class USphereComponent* ProxSphere;
I think this means create a class, but is this class a pointer?
But the result is just creating an object called ProxSphere from an existing class USphereComponent.
What does this syntax actually mean, and what is its usage?
class Someotherclass; // That has not been defined yet
class HelloWorld
{
Someotherclass* my_pointer;
};
Or an alternative:
class HelloWorld
{
class Someotherclass* my_pointer;
};
The first one is obviously the correct one if you have multiple pointers (or references) to such class that has not been defined yet.
Is the second better? (I don't know) if you only need to do it once, otherwise doing
class HelloWorld
{
class Someotherclass* my_pointer;
class Someotherclass* my_pointer2;
class Someotherclass* my_pointer3;
void func(class Someotherclass* my_pointer, class Someotherclass& my_ref);
};
may not be the best.
Jts's answer is correct. I'd like to add a use case for it:
This is mostly used when you have a circular class dependency.
Like:
class A { B* binst; };
class B { A* ainst; };
That wouldn't compile since B isn't previously known.
Therefore you would first declare class B.
class B;
class A { B* binst; };
class B { A* ainst; };
Or as mentioned, you can use syntactic sugar:
class A { class B* binst; };
class B { A* ainst; };
Such a dependency might be a code smell. It also might be ok or even necessary. If you have it, you should carefully think if you can't do it in some other yet convenient way.
That particular syntax is called a "forward declaration". It is used to declare a type that has not been defined yet.
This is basically telling the compiler "There exists a class type named USphereComponent that you haven't seen yet that will come up later in the code. Please don't yell at me if you see pointers of that type". This allows you to declare pointer and reference for that forward-declared type.
Writing:
class USphereComponent* ProxSphere;
Is really just the equivalent of writing this:
class USphereComponent;
USphereComponent* ProxSphere;
The only difference with the second syntax, is that you only need to forward-declare the type once when you do it like this class USphereComponent;, otherwise you need to use the first syntax and add the class keyword before each usage of USphereComponent.
There are two main reasons why you may want to use a forward declaration:
This is probably the most common usage of forward-declaration in Unreal Engine. In header (.h) files, forward-declaration allows you to use pointer of classes for which you did not #include the corresponding header file. In our particular example that means that forward-declaring USphereComponent means that we don't need a #include "SphereComponent.h" statement (if we're just trying to pass a USphereComponent around that is).
Typically when that happens, the #include statement is simply done in the .cpp file. There are mainly two advantages of reducing the number of includes in your header files:
Compilation times are faster. Mind you, this mostly has significant impact on a codebase as big as Unreal's.
This reduces the number of public dependencies of you module (by making them "private" since your includes are now in your .cpp). This makes your module easier to be depended upon and also makes its interface cleaner.
Like other answers have said, forward-declaration can be used to break circular dependencies when you have two types that depends on each other in the same file:
class B;
class A
{
B* foo;
};
class B
{
A* bar;
};
I'm converting my old c++ program into OOP and as things grow bigger I'm splitting it per class in .h and .cpp files. The first class compiled nicely into an object file. But my second class is dependant on that first class and now I run into problems. Here my very simplified "all in a single file" code that works:
class A {
public:
void amethod(int) {
....code....
}
};
A a_obj; //object creation
class B {
public
void bmethod(void) {
a_obj.amethod(int);
}
};
B b_obj; //object creation
main() {
b_obj.bmethod();
}
After deviding the code over different files my .h files look like:
//file A.h:
class A {
public:
void amethod(int);
};
//file B.h
#include "A.h"
class B {
public
void bmethod(void);
};
In the implementation of class B there is the call to a_obj.amethod() and even I understand that g++ has no way to know that a_obj is an object of class A as I did not even include the a_obj object creating anywhere in the code.
How to solve this ? Is it something simple that I need to put the object creation somewhere in my .h or .cpp file (note that lots of other classes are using the same amethod()). I can not make everything static as I also have classes with multiple objects (in fact the same way of working is all over the program). Or is this way of working completely wrong (which would explain why I can not find any solution for this).
Is suggest you put more efforts in defining your interfaces.
If class B needs an instance of A to work, use parameters to pass an A:
class B {
public
void bmethod(A & a_obj) {
a_obj.amethod(int);
}
};
main() {
A a_obj;
B b_obj;
b_obj.bmethod(a_obj);
}
The problem is that your original code uses global data (i.e. the declarations of a_obj and b_obj are global). Globals are generally a bad idea because they can cause several problems. The 'proper' OOP way to do it would be to instantiate those objects in main(), and pass them to whatever other objects need to access them. You could pass references, pointers, or copies, depending on your needs.
With that said, if you really want to continue doing it with global data, then you can use an extern declaration. In each *.cpp file where you access a_obj, include this:
extern A a_obj;
That basically tells the compiler that there is an object with that name, but it exists somewhere else. I really don't recommend this approach if you're serious about learning OOP though.
I guess you are planning to use a_obj as global variable in other implementation file (.cpp).
So in header file B.h type extern reference to this instance.
extern A a_obj;
This declaration should help compile your B.cpp file. And ask actual instance a_obj during linking.
I didnt try this code, but telling by my experience and my practice(way) of coding. Hope this solution helps, else am sorry.
First, in order to call A::amethod() class B needs the full definition of class A and its amethod(). So you need to #include A.h before B.h in your .cpp files.
Next, if you address concrete a_obj object, you need to specify what that object is in order to link properly. In you first variant it was global object, so if it is what intended you can write: in A.cpp:
A a_obj;
in B.cpp:
extern a_obj;
// here you can call a_obj methods
But if these classes are so related that one calls methods of another, and also as I catched you need several objects of A and B, consider to connect these classes through inheritance:
class B : public A {
public:
void bMethod(int n) {
aMethod(n); // base class method call
}
// ...
or through delegation:
class B {
A m_A;
public:
void bMethod(int n) {
m_A.aMethod(n);
}
// ...
As mentioned earlier the way
void bMethod(A& a) {
a.aMethod();
}
will work, but the language has built-in means to express classes relationships.
How to implement is more design question, you can read more about this in Stroustrup 3rd edition, '24.3.5 Use Relationships'.
In C++ you can also pass a pointer to a member function of one class into the member function of another class to call a method from completely unrelated class (say, some callback), you can use boost::function and boost::bind for this. But it is advanced technique.
I'm using boost::intrusive_ptr as my reference counted smart pointer. I'm using something like this:
http://www.codeproject.com/KB/stl/boostsmartptr.aspx#intrusive_ptr%20-%20lightweight%20shared%20pointer
This seems a good idea, because it simplifies the declaration of a new Reference counted class, just inheriting from it. The problem comes with forward declarations. There are a lot of places where I want to use a pointer to a type not yet decladed in a class definiton and it is not possible, because the 2 methods that handle ref count need to know if the type inherits from CRefCounted or not.
If I try to include the dependencies before the declaration of the intrusive_ptr it is ok, but then, I get a lot of cyclic includes.
How would you handle this scenario?
I think you can solve this using templates functions for intrusive_ptr_add_ref and intrusive_ptr_release as follows:
namespace boost {
template<class T> void intrusive_ptr_add_ref(T* p) { ++(p->references) }
template<class T>void intrusive_ptr_release(T* p) {
if (--(p->references) == 0)
delete p
}
};
You'll also need to adapt the friend declarations in CRefCounted like
template class<T> friend void ::boost::intrusive_ptr_add_ref(T*);
template class<T> friend void ::boost::intrusive_ptr_release(T*);
Using these declarations, you can use intrusive_ptr on forward-declared classes like
class A;
class B {
::boost::intrusive_ptr<A> _myPtr;
};
class A : public CRefCounted {
};
This solution has the drawback (theoretically...), that you define a pair of add_ref/release functions for every subclass of CRefCounted, but I think that the compiler will choose to use inlining anyway, so this can be neglected.
I've been using a similar RefCounted base class a lot and I started wondering why do I never have this problem. And it's because I tend to hide implementation details in source files. Consider the following header file of class B:
//File: B.h
#include <boost/intrusive_ptr.hpp>
class A;
class B
{
public:
B();
~B();
boost::intrusive_ptr<A> foo();
void foo2(const boost::intrusive_ptr<A> p);
boost::intrusive_ptr<A> p;
};
It works, because even though it is using intrusive_ptr, it doesn't need to instantiate its constructor or destructor. Therefore it doesn't need to know anything about the class A.
The place where it needs to know about A is in the source file. (And also in places where foo/foo2 are called). B's constructor and destructor implicitly call intrusive_ptr< A>'s constructor/destructor, so A's definition must be available.
//File: B.cpp
#include "B.h"
#include "A.h" //Include header where A is defined.
B::B() { }
B::~B() { }
//Other member functions...
I don't know if this helps in your case, but it's something to think about. :)
It's been a long time since I've done C++ and I'm running into some trouble with classes referencing each other.
Right now I have something like:
a.h
class a
{
public:
a();
bool skeletonfunc(b temp);
};
b.h
class b
{
public:
b();
bool skeletonfunc(a temp);
};
Since each one needs a reference to the other, I've found I can't do a #include of each other at the top or I end up in a weird loop of sorts with the includes.
So how can I make it so that a can use b and vice versa without making a cyclical #include problem?
thanks!
You have to use Forward Declaration:
a.h
class b;
class a
{
public:
a();
bool skeletonfunc(b temp);
}
However, in many situations, this can force you to work with references or pointers in your method calls or member variables, since you can't have the full types in both class headers. If the size of the type must be known, you need to use a reference or pointer. You can, however, use the type if only a method declaration is required.
Use forward declaration : http://en.wikipedia.org/wiki/Forward_declaration