I've been looking at examples for a component-based system and in some of the examples, I noticed the usage of class names outside of other classes like in the example below. What is the purpose/function of creating class Foo; and class Bar; and what is this called?
#pragma once
#include "foo.h"
#include "bar.h"
class Foo; // ???
class Bar; // ???
class Example
{
public:
Example() :
m_pExample(0) {}
virtual ~Example() {}
void something(const Foo& foo, const Bar& bar);
private:
Example* m_pExample;
};
It is called a forward declaration and declares class name as a valid but leaves out the definition. This mean that you can use the name as a type before the definition is encountered.
What are forward declarations in C++?
Those are called forward declaration
This help the compiler know that the type exists and it knows nothing about its size, members, and methods.
Therefore its a an incomplete type too.
Actually if you already have #include "foo.h" and #include "bar.h" (assuming the class definition of each class is already in its related .h file), I don't see why you should have the two class Foo; and class Bar; statement.
Usually the reason of putting the class Foo; and class Bar; is that you are going to provide the definition of the two classes yourself.
Example:
#pragma once
class Foo;
class Bar;
class Example
{
public:
Example() :
m_pExample(0) {}
virtual ~Example() {}
void something(const Foo& foo, const Bar& bar);
private:
Example* m_pExample;
};
class Foo
{
// Definition of Foo class goes here...
;
};
class Bar
{
// Definition of Bar class goes here...
;
};
Related
This question already has answers here:
When can I use a forward declaration?
(13 answers)
Closed 5 years ago.
I reproduce an error with the following simple file.
It says:
field has incomplete type 'Foo'
bar.h:
class Foo;
class Bar{
private:
int x_;
Foo foo_; // error: incomplete type
public:
void setx(int x) {x_ = x;};
void increment(int);
};
class Foo{
public:
void run(int y,Bar& bar) {bar.setx(y);};
};
void Bar::increment(int i){foo_.run(i,*this);}
Member foo_ must not be a reference or a pointer. The reason for this is that in my actual code, I cannot initialize Foo in the initialization list of Bar.
Your problem can be reduced to this:
class Foo;
class Bar{
Foo foo_; // error: incomplete type
};
Here you did a forward declaration for type Foo, i.e. a declaration without a complete definition: that's enough in C++ to declare a pointer, but not a concrete instance as you did in Bar.
Either give a complete definition to your class:
class Foo{
// put details here
};
class Bar{
Foo foo_; // OK
};
Or use (smart) pointers, e.g.:
class Foo;
class Bar{
std::unique_ptr<Foo> foo_; // OK
};
Or change order declaration as pointed by Bartek Banachewicz.
In this case it's simple enough: since Foo only uses a reference to Bar, flipping them around will do the trick:
class Bar;
class Foo{
public:
void run(int y,Bar& bar);
};
class Bar { ... };
void Foo::run(int y, Bar& bar) {
bar.setx(y);
}
You also need to move the body of Foo::run below, because it's actually using the Bar member function.
In the book "C++ primer" there is a section about class declarations and definitions. I don't understand everything about this sentence :
data members can be specified to be of a class type only if the class has been defined.
I don't understand the logic behind this sentence. How do you specify a data member to be of a class type, what does this action mean?
It means, for declaration of a non-static class data member of class type T, T is required to be complete.
(In general, when the size and layout of T must be known.)
e.g.
class foo; // forward declaration
class bar {
foo f; // error; foo is incomplete
};
On the other hand,
class foo {}; // definition
class bar {
foo f; // fine; foo is complete
};
I believe it means that this will compile:
class A
{
public:
A() {/* empty */}
};
class B
{
public:
B() {/* empty */}
private:
A myClassMember; // ok
};
.... but this will not:
class A; // forward declaration only!
class B
{
public:
B() {/* empty */}
private:
A myClassMember; // error, class A has only been declared, not defined!
};
It means this specification of member is not valid, because A is declared but not defined:
class A;
class B {
A member;
};
One reason why this isn’t allowed is because sizeof(A) is unknown.
This, however, is valid, because A is defined:
class A {
int value;
};
class B {
A member;
};
And this is valid even if A is not defined (only declared), because member is not of class type, but pointer type:
class B {
A* member;
};
So lets say I have a class called Foo and another called Bar. Bar contains an instance of Foo and I have a function in Foo that takes Bar as a parameter. However, when I #include "Bar.h" in Foo to allow Foo to see Bar I get this error on the lines that Bar is referenced on:
error: ISO C++ forbids declaration of 'Foo' with no type
I'm guessing this is because both of the classes rely on each other to compile. Is there any way to get around this?
EDIT: Both of these classes have header files where the other class is referenced inside a #ifndef declaration.
In Foo.h instead of including Bar.h you need to use the forward declaration class Bar;. Note that for this to work you need to take the parameter Bar as a reference or a pointer in Foo class.
class Foo;
class Bar
{
};
and
class Bar;
class Foo
{
};
But this might be a result of a wrong design!!
You'll need to use a forward declaration for at least one class:
Foo.h:
#include "Bar.h"
class Foo {
};
Bar.h:
class Bar;
#include "Foo.h"
class Bar {
};
Also beware that you cannot easily reference members of Bar in Foo.h (they're not declared). So any inlined members that need Bar will have to go in Foo.cpp (or .cc if you prefer). You also cannot have a Bar as a value member of Foo.
So:
class Bar {
Foo f; // OK. Compiler knows layout of Foo.
};
class Foo {
Bar b; // Nope. Compiler error, details of Bar's memory layout not known.
Bar *b; // Still OK.
};
This is especially tricky for templates. See the FAQ if you have troubles.
Use references or pointers for parameters and forward declarations. E.g.
//foo.h
class Bar;// the forward declaration
class Foo {
void myMethod(Bar*);
};
//foo.cpp
#include "bar.h"
void Foo::myMethod(Bar* bar){/* ... */}
//bar.h
#include "foo.h"
class Bar {
/*...*/
Foo foo;
};
I want to hide an implementation in implementation file. If the object is not public, I don't want the object's header to leak everywhere my class is used.
Suppose I have header file A.h for my class A:
#include "Foo.h"
class A{
private:
Foo foo;
public:
do_stuff();
};
Now wherever I would include A.h, Foo.h also would be included. But I have no use for class Foo anywhere outside of class A. I would rather not have this #include "Foo.h" line. Is there any way to move the declaration of 'foo' variable inside the implementation A.cpp?
I suspect one possible solution involves adding a layer of abstract class (interface analogy). Is it the best solution?
Thank you.
Use a pointer to Foo and allocate it dynamically, rather than using a member object. Then you only need to include Foo.h in A.cpp.
class Foo;
class A{
private:
Foo* foo;
public:
do_stuff();
}
David's got the right answer. I'll refer to this article for a little more treatment on this kind of "opaque pointer" trick, as you can get more elaborate with it, depending on your needs:
http://en.wikipedia.org/wiki/Opaque_pointer
Also, it's a good idea to use shared_ptr types for this purpose instead of raw pointers like the sample. This will take care of cleaning up resources for you automatically, once the last reference to Foo goes out of scope.
Yes. Choose yer poison!
Option 1. Forward declaration in interface.
class A {
private:
class Foo;
Foo* foo;
};
Option 2. ABC.
// A.hpp
class A {
public: virtual void do_stuff() = 0;
};
// A.cpp
class A_impl : public A {
class Foo { /*etc*/ };
Foo foo;
void do_stuff (){...}
};
Option 3. Private is private. It's "hidden" as far as the public API goes, which is all that matters:
class A {
private:
class Foo {
...
};
private_::Foo foo;
public:
do_stuff();
};
Option 4. Just put the declaration in a "non-public" namespace.i.e., omit it from documentation and name it something to frighten away prying eyes:
namespace private_ {
class Foo {
...
};
}
class A {
private:
private_::Foo foo;
public:
do_stuff();
};
I know that I can forward declare a class as follows:
class Foo;
// ... now I can use Foo*
However, can I do something like this:
class Bar {
public:
virtual void someFunc();
};
// ... somehow forward declare Class Foo as : public Bar here
someFunc(Foo* foo) {
foo -> someFunc();
}
class Foo: public Bar {
}
?
Thanks!
You can forward declare Bar as class Bar; and change the signature of someFunc to take a Bar* as parameter. Since someFunc() is a virtual method in the base class, it should work.
After your forward declaration Foo becomes an incomplete type and it will remain incomplete until you provide the definition of Foo.
While the Foo is incomplete any attempt to dereference a pointer to Foo is ill-formed. So to write
foo->someFunc();
you need to provide Foo's definition.