Reputation: 4253
I have a Class with the following .h
class Book; //forward declaration of Book
class Reader
{
public:
Reader();
void SetBook( Book );
private:
Book book_; // Error Reader::book_ uses undefined class Book
}
and .cpp contains
#include "book.h"
void Reader::SetBook( Book book ) { this->book_ = book; }
// Error C2440 cannot convert from Book to int
I can't see why this forward declaration would does not work. Also, it does not throw an error for the 'Book' type being used in the declaration
void SetBook (Book )
Any suggestions what's wrong, here?
Upvotes: 0
Views: 926
Reputation: 741
Here is the rule of thumb when it comes to the problem of forward declaration or definition:
forward declaration is the Label and definition means opening the box.
Whether the internal information(i.e. size, memory layout, member data/function) of the type are being used, or just its name
class Book; // forward declaration of Book. Right now we know nothing about Book's internal info except it's unique ID, i.e. the name of type: Book.
Book *ptr; // OK, pointer's size is fixed and it has nothing to do with Book.
Book **pptr; // Ok, same with previous
ptr->someDataMember = bla; // ERROR, we don't know what is in a Book object.
ptr->callDataFunc(); // ERROR
++ptr; // ERROR, need to know the sizeof Book, since ++ptr equals to (char*)ptr + sizeof(Book)
++pptr; // OK
*pptr++; // OK, *pptr is a Book*, which size is fixed.
**pptr++; // ERROR
template<typename T>
class DontUseT{};
DontUseT<Book> dut; // OK, we don't use Book's internal information here
int foo(Book *b) { return sizeof(b);} // OK
int foo(Book&b) { return 0;} // OK
int foo(Book&b) { return sizeof(Book);} // ERROR
int foo(Book); // OK
int foo(Book) {} // ERROR, inside the definition it's supposed to access its arguments
Upvotes: 1
Reputation: 717
Here is an alternate and totally informal way to see it:
If you are just writing labels saying "Pot of Honey", you just need to know how to spell it.
Now, if you want to stick the label on the pot and bring it home to eat it, you need to know what the darn pot looks like and how to open it
Upvotes: 0
Reputation: 29017
In the header file Book
is an incomplete type (the compiler knows it is a type, but not how big it is, or what its members are).
It is fine to declare a function (SetBook
) with arguments that are of incomplete type, but to declare a member variable (book_
), the type needs to be complete (fully declared). In particular, the compiler needs to know how big Book
is, so that it can decide how big Reader
is.
One solution is to make book_
be a smart pointer (you could make it a raw pointer, but why create all the memory handling headaches?). Then the compiler knows that it needs a pointer (and doesn't care how big the pointed to object is).
Upvotes: 2
Reputation: 5346
A forward declaration is enough when you declare a pointer or a reference. Because your member book_
is of type Book the compiler needs the definition of Book
when processing the header.
Upvotes: 6