chrise
chrise

Reputation: 4253

c++ why does this forward declaration fail?

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

Answers (4)

Jason L.
Jason L.

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

giant_teapot
giant_teapot

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

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

piwi
piwi

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

Related Questions