Forward declaration of class in C++ [duplicate] - c++

This question already has answers here:
How to create two classes in C++ which use each other as data?
(2 answers)
When can I use a forward declaration?
(13 answers)
Why does std::vector work with incomplete types in class definitions?
(1 answer)
Closed 4 months ago.
I want two classes to 'include' each other in their variables.
#include <vector>
class Bar;
class Foo {
public:
Bar b1;
};
class Bar {
public:
std::vector<Foo> f1;
};
I get this error error: field 'b1' has incomplete type 'Bar' while trying to compile. What's going wrong?

Your C++ compiler doesn't know how large a Bar object is yet, so it can't be included in Foo. However, a pointer to Bar is a known size, so you can use that.
class Bar;
class Foo {
public:
Bar *b1;
};

When declaring this:
class Bar;
class Foo {
public:
Bar b1;
};
Think about it, Foo has no idea what Bar "looks" like, it just knows that Bar is a class, so what the sizeof Bar and therefore Foo should be?
On the other hand, when using a pointer, it doesn't need to know the size of the object, because the sizeof pointer is fixed and known, therefore you could do what #Chris proposed.
But since C++17, std::vector also accepts incomplete type so you could define this in the header:
bar.h
#include <vector>
class Foo;
class Bar
{
public:
std::vector<Foo> f1;
};
foo.h
#include "bar.h"
class Foo
{
public:
Bar b1;
};
Then include both bar.h and foo.h in both .cpp file.

Related

How to Have Two Different Object Methods Use Each Other as Paramters

header.h
class Foo{
public:
void fooFunction(std::map <std::string, Bar> &);
}
class Bar{
public:
void barFunction(std::map <std::string, Foo> &, Foo &);
}
When I try to compile this, I get an error saying Bar is not declared in the scope of fooFunction, and when I switch the order of the declarations, I get an error saying Foo is not in the scope of barFunction.
How can I make them be in the scope of each other? If I need multiple header files, how should I set that up in my makefile and #include s?
You can simply forward-declare the other class in the header that requires it:
class Bar;
class Foo
{
public:
void fooFunction(std::map <std::string, Bar>&);
};
class Bar
{
public:
void barFunction(std::map<std::string, Foo>&, Foo &);
};
This works provided that Foo does not use Bar by value anywhere until after Bar has been defined. That means storing it as a member, passing as parameter, returning value of that type. In this case you're fine, since the Foo parameters are passed by reference.
Note that even though your std::map stores type Bar by value, this is still okay because it's a template and is not resolved until you use it, at which time Bar will be defined.

Field has incomplete type in forward declaration [duplicate]

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.

Declaring property in a class that has the type of another one in C++ [duplicate]

This question already has answers here:
How do you use the non-default constructor for a member?
(5 answers)
Closed 7 years ago.
I'm new to C++, but I have previous programming experience in PHP and C# (OOP).
What I have is: two classes one of which has a private property with the type of the other class.
Source:
class Foo
{
public:
Foo(int n)
{
}
};
class Bar
{
private:
Foo foo;
public:
Bar()
{
this->foo = Foo(10);
}
};
Bar bars[123];
What I'm trying to do is declare a property of Foo with a constructor in Bar. Unfortunately, the way I did it doesn't work. It gives a series of errors e.g.
no matching function for call to 'Foo::Foo()'
How do I get it working?
Thanks for your reply.
You need to initialize Foo properly in a member initialization list, like so:
class Bar
{
private:
Foo foo;
public:
Bar() :
foo(10)
{}
};
Otherwise, what happens is that the compiler first tries to initialize this->foo with a default constructor before getting into the body of your constructor. Since Foo doesn't have one, it fails to compile.

Error with two classes that #include each other

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;
};

Is it possible not to include a class variable in a class header file?

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();
};