I am getting the
Incomplete type is not allowed
error. Obviously I don't understand how forward declarations work. I know I cannot use methods in the header file, but what about in implementation?
Here is the code:
Foo.h:
#pragma once
class Bar;
class Foo {
const Bar &mBar;
public:
Foo(const Bar &bar);
int getVal() const;
};
Foo.cpp:
#include "Foo.h"
Foo::Foo(const Bar &bar) : mBar(bar) {}
int Foo::getVal() const {
return mBar.getVal();
}
Bar.h:
#pragma once
class Bar {
public:
Bar();
int getVal();
};
Bar.cpp:
#include "Bar.h"
Bar::Bar() {}
int Bar::getVal() {
return 5;
}
mBar.getVal() is what is causing the error. However it is in implementation file. Is this also not permitted?
Include in file Foo.cpp header Bar.h
Foo.cpp:
#include "Foo.h"
#include "Bar.h"
Foo::Foo(const Bar &bar) : mBar(bar) {}
int Foo::getVal() const {
return mBar.getVal();
}
Or include header Bar.h in header Foo.h
Foo.h:
#pragma once
#include "Bar.h"
class Foo {
const Bar &mBar;
public:
Foo(const Bar &bar);
int getVal() const;
};
Take into account that function Bar::getVal must have qualifier const
int getVal() const;
Otherwise you will get one more compilation error because this non-const function is called from a const function of class Foo.
int Foo::getVal() const {
return mBar.getVal();
// ^^^^^^^^^^^
}
Think from the perspective of the compiler. When it is compiling the source file Foo.cpp and comes to the statement mBar.getVal(), it has no idea about the members of mBar! All it knows is that mBar is a reference to a const Bar object. But without making the Bar class definition visible to the compiler you cannot access it's members.
Typically, you do forward declarations in header files to avoid pulling in too many header files( which is important if the header file is part of externally visible API). In the source file you should include the header files that contain the class definition; in this case Bar.h
Related
I'm having an issue with a friend function.
Basically I have a class in a header (inside a namespace), which contains a friend function:
namespace X {
class Foo {
// private members
friend void SomeNamespace::someFunction(const Foo& foo);
}
And in a separate header, I have the function which I'm trying to make a friend, which is inside a namespace:
#include "classHeader.h"
namespace SomeNamespace {
void someFunction(const X::Foo& foo);
}
This doesn't seem to work, as someFunction can't access Foo's private members, apparently.
After some research I found out that I was missing a forward declaration, so I tried adding it:
namespace X{class Foo}; // Forward declare class
void SomeFunction(const X::Foo& foo);
But this does not seem to work either. What's wrong?
To expand on my comments, lets say you have the following three files:
Foo header file
#include "SomeNamespace.h"
namespace X
{
class Foo
{
friend void SomeNamespace::SomeFunction(const Foo&);
};
}
SomeNamespace header file
namespace X
{
// Forward declaration
class Foo;
}
namespace SomeNamespace
{
void SomeFunction(const Foo&);
}
SomeNamespace source file
#include "SomeNamespace.h"
#include "Foo.h"
void SomeNamespace::SomeFunction(const Foo& foo)
{
}
[Note: Things like actual contents, as well as header include guards, purposefully omitted for brevity]
One of the header files needs to use forward declaration only, while the other can use #include.
The important part is that you must include all needed header files in the source file where you define (implement) the classes and functions.
Here's one way:
s.hpp
#pragma once
class Foo; // forward declaration is enough here since you only use a reference
namespace SomeNamespace {
void someFunction(const Foo& foo);
}
f.hpp
#pragma once
#include "s.hpp" // the function declaration of someFunction is needed
class Foo {
public:
Foo(int X);
friend void SomeNamespace::someFunction(const Foo& foo);
private:
int x;
};
s.cpp
#include "f.hpp" // Foo's definition is needed here
#include "s.hpp"
#include <iostream>
namespace SomeNamespace {
void someFunction(const Foo& foo) {
std::cout << foo.x << '\n'; // private member now accessible
}
}
f.cpp
#include "f.hpp"
Foo::Foo(int X) : x(X) {}
I have this error for the following code
incomplete type ‘Foo::Pimpl’ used in nested name specifier
AnotherFoo.hpp
struct AnotherFoo {
void methodAnotherFoo(Foo &);
};
AnotherFoo.cpp
#include "Foo.hpp"
#include "AnotherFoo.hpp"
void AnotherFoo::methodAnotherFoo(Foo &foo) {
// here i want to save the function pointer of methodPimpl(), std::function for ex:
std::function<void(void)> fn = std::bind(&Foo::Pimpl::methodPimpl, foo._pimpl); // <-- Here i am getting the error
}
Foo.hpp
struct Foo {
Foo();
class Pimpl;
std::shared_ptr<Pimpl> _pimpl;
};
Foo.cpp
#include "Foo.hpp"
struct Foo::Pimpl {
void methodPimpl(void) {}
};
Foo::Foo() : _pimpl(new Pimpl) {}
main.cpp
#include "Foo.hpp"
#include "AnotherFoo.hpp"
int main() {
Foo foo;
AnotherFoo anotherFoo;
anotherFoo.methodAnotherFoo(foo);
}
Does anyone have a good solution for how to fix this?
The main goal that I am trying to achieve is to keep the signature of the methodAnotherFoo method hidden from the header files.
The only file in which you may access details of Foo::Pimpl is Foo.cpp, the file in which it is defined.
You may not access it in AnotherFoo.cpp.
Your choices are:
Change the implementation of AnotherFoo::methodAnotherFoo to use only the public interface of Foo.
Move the implementation of AnotherFoo::methodAnotherFoo to Foo.cpp.
If AnotherFoo.cpp needs direct access to the implementation object it is going to have to see the definition of that type, there is no way around that. Perhaps add a "detail/foo.h" header that is meant for internal use like this.
Your Pimpl implementation is not correct. It should hide details while you are trying to access them directly from methodAnotherFoo. So you should make implementation details private and provide a public proxy methods to manipulate stored implementation:
class Foo
{
public: Foo();
public: void method(void);
private: class Pimpl;
private: std::shared_ptr<Pimpl> _pimpl;
};
// Foo.cpp
struct Foo::Pimpl
{
void methodPimpl(void) {}
};
Foo::Foo() : _pimpl(new Pimpl) {}
void Foo::method(void) {_pimpl->method();}
And change the rest of the code to utilize those proxy methods instead of digging to implementation details:
void AnotherFoo::methodAnotherFoo(Foo &foo)
{
std::function<void(void)> fn = std::bind(&Foo::method, foo);
}
One solution that i found is to move the Pimpl implementation to AnotherFoo.cpp
Why if I have
in foo.h:
class Foo
{
}
void Bar(const Foo& foo);
it works but:
in foo.h:
class Foo
{
}
in bar.cpp
#include "foo.h"
void Bar(const Foo& foo);
doesn't work (unknown type name 'Foo' is its exact words)?
I don't know what about my question isn't specific and forward declarations don't work they just create a error 'duplicate symbol' so im just going to post the code im working with
in creatures.h
#ifndef CREATURES_H_
#define CREATURES_H_
#include <string>
#include "textio.hpp"
class Creature {
private:
protected:
int statBlock[10];
public:
std::string name = "foo";
Creature ();
void ai(int);
};
class Dwarf : public Creature {
private:
public:
std::string name = "Dwarf";
Dwarf (int);
void defaultDwarfGen();
};
main.cpp
#endif
#include "creatures.hpp"
#include "textio.hpp"
#include <iostream>
int main(int argc, char const *argv[]) {
Dwarf creature_1(0);
return 0;
}
textio.hpp:
#ifndef TEXTIO_H
#define TEXTIO_H
#include <iostream>
#include "creatures.hpp"
void challenge(const Creature& param);
#endif
Your problem is that you are including textio.hpp in creatures.hpp so first time that compiler see function void challenge(const Creature& param)Creature class isn't defined.
When you include createures.hppin textio.hpp CREATURES_H_ is already defined and bypass inclusion)
You can fix it deleting this include or declaring a forward definition for Creature class
In order to answer this question properly, you must provide foo.h, foo.cpp, bar.h, and bar.cpp
In short:
To make use of Bar in foo.h, foo.h must have the declaration for Bar.
To make use of Foo in bar.h, bar.h must have the declaration for Foo.
To make use of Bar in foo.cpp, foo.h or foo.cpp must have the declaration for Bar.
To make use of Foo in bar.cpp, bar.h or bar.cpp must have the declaration for Foo.
When I say, "must have declaration for", you can #include the appropriate header.
If you are trying to use Foo in Bar and Bar in Foo, then you've got a circular reference. The way we overcome this is with a forward declaration.
You can read about forward declarations here: https://isocpp.org/wiki/faq/misc-technical-issues#forward-decl
I have the following two classes:
Foo which has constructor Foo(Bar*, int, int)
and Bar which calls new Foo(this, int, int)
I assumed that forward declaring Foo in Bar.h and/or Bar in Foo.h would solve the issue.
(The error returned is "undefined reference" on new Foo)
I"m using Clang to compile.
The linking order as it stands (but the same error happens in both cases) is Foo then Bar.
Any thoughts as to what I am doing wrong?
The code is roughly as follows. I cannot display any real code fragments unfortunately
#include Bar.h
class Bar ;
class Foo {
public:
Foo(Bar* bar, int arg1, int arg2) ;
void method1() {
I access bar->field here
}
And the code for Bar is then
#include Foo.h
class Bar {
public:
Bar() {
Cache* cache = new Cache(this, 0, 0) ;
}
It should look something like this (leaving out include guards):
foo.h
class Bar;
class Foo {
public:
Foo(Bar*, int, int);
};
bar.h
class Bar {
public:
Bar();
};
foo.cc
#include "foo.h"
// Note: no need to include bar.h if we're only storing the pointer
Foo::Foo(Bar*, int, int) { ... }
bar.cc
// Note: the opposite order would also work
#include "bar.h"
#include "foo.h"
Bar::Bar() {
new Foo(this, int, int);
}
If you're getting "undefined reference" from the linker, you probably declared Foo::Foo with a different signature than you defined it with, or did not define it at all, or are not linking with the object file it's compiled into.
I came across a circular dependency issue, where the order of inclusion of headers matters. This problem is similar, but it does not document the solution where one class instantiates an object of the other.
Problem:
I have two classes: Foo and Bar. Bar is templatized. (Foo may or may not be templatized).
Foo has an instance of Bar, and Bar has a pointer of type Foo, and the implementation of Bar needs to access members of Foo through this pointer.
Foo and Bar have to be implemented within separate files. As Bar is templatized, its declaration and implementation have to be in the same file.
In the following code, if main.cpp includes Bar.h before Foo.h the code compiles, and does not when Foo.h is included before Bar.h. Is there a way to make the code compile, irrespective of the order in which headers are included in main.cpp?
Foo.h
#ifndef FOO_H
#define FOO_H
#include"Bar.h"
class Foo
{
public:
Bar<> B;
void fooStuff(){};
};
#endif
Bar.h
#ifndef BAR_H
#define BAR_H
class Foo;
template<int N=0> class Bar
{
public:
Foo * F;
void barStuff();
};
#include"Foo.h"
template<int N> void Bar<N>::barStuff()
{
F->fooStuff();
};
#endif
main.cpp
#include"Foo.h"
#include"Bar.h"
int main()
{
Foo F;
F.B.barStuff();
};
Yes: declare Foo before Bar, since Bar only uses a pointer, which doesn't need a full definition. Then define Foo after Bar - it uses an object, and so it does need the definition.
class Foo;
template<int N> class Bar
{
public:
Foo * M;
void barStuff();
};
class Foo
{
public:
Bar<42> B;
void fooStuff(){}
};
template<int N> void Bar<N>::barStuff()
{
M->fooStuff();
}
In general, you need the full definition for anything that needs any properties of the class, such as its size or members, and only a declaration to use the class name when declaring functions, pointers or references.
I need Bar to be included before Foo, no matter in what order they're included in main.cpp. The following hack seems to work:
In Foo.h, include Bar.h outside the header guards. As Bar has header guards too, it does not get included multiple times.
Foo.h
#include"Bar.h"
#ifndef FOO_H
#define FOO_H
class Foo
{
public:
Bar<> B;
void fooStuff(){};
};
#endif
Bar.h
#ifndef BAR_H
#define BAR_H
class Foo;
template<int N=0> class Bar
{
public:
Foo * F;
void barStuff();
};
#include"Foo.h"
template<int N> void Bar<N>::barStuff()
{
F->fooStuff();
};
#endif
main.cpp
#include"Foo.h"
#include"Bar.h"
int main()
{
Foo F;
F.B.barStuff();
};