Jump to content
  • Advertisement
Sign in to follow this  
madmike82

Why does "class" at the top of a header file work?

This topic is 3818 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Basically, if I have the following:
// some header file

class foo;

class bar
{
 foo* f;
};

I've seen this done in larger software projects so I thought I'd give it a shot, but I can't seem to find an explanation why simply putting "class classname" at the top of a header file works whereas trying to include the header file that contains the class declaration occasionally results in complier errors (due to multiple headers trying to include each other).

Share this post


Link to post
Share on other sites
Advertisement
class foo; is a forward declaration; it just tells the compiler that foo is a class, and you'll give it the definition of it later.

Because the compiler doesn't know the classes size or anything, you can only use pointers or references to the class, and not call any class methods until you include the header.

Usually you'd use the forward declaration in the header, so you don't pull foo's header into that file, and then you'd #include "foo.h" in bar.cpp, so you can call it's methods and so on.

Share this post


Link to post
Share on other sites
Well, like you said, if you have circular dependendies (foo.h includes bar.h and bar.h includes foo.h), you'll get this after the preprocessing stage:


class foo
{
bar* b; // uh, what is bar?
};

class bar
{
foo* b; // I know foo!
};


So now foo can't find bar. Switch the include order, and bar can't find foo.

The solution is to tell the compiler that there is a class "foo" (or bar) but not declare its contents.


class bar; // Hey, there's a class named bar

class foo
{
bar* b; // Ah, I know that bar is a class, so I know how make a pointer to it
};


This only works for pointers, because to define pointers the compiler doesn't need to know the contents of the type.


This is what everyone will say. However, I'm myself a bit confused about one thing: this assumes that pointers are always the same size. In C, yes. In C++, not necessarily, AFAIK. If you have classes with, say, multiple virtual inheritance, pointers to such classes can take up multiple words in certain compilers (MSVC++). So how does this work with forward declarations? How can the compiler be sure about a pointer's size if it knows nothing about the type's inheritance structure?

Share this post


Link to post
Share on other sites
Quote:
Original post by Mike nl
I'm myself a bit confused about one thing: this assumes that pointers are always the same size. In C, yes. In C++, not necessarily, AFAIK. If you have classes with, say, multiple virtual inheritance, pointers to such classes can take up multiple words in certain compilers (MSVC++). So how does this work with forward declarations? How can the compiler be sure about a pointer's size if it knows nothing about the type's inheritance structure?

A pointer to an object is a pointer to an object. C++ and C are the same in this respect, otherwise there would be no compatibility between billions of lines of C code and C++.

There is no reason why multiple inheritance or virtual inheritance would affect a pointer-to-object size. No so with pointer-to-member, but pointer-to-object is not different than, say, pointer-to-int.

Share this post


Link to post
Share on other sites
Quote:
Original post by Bregma
No so with pointer-to-member,

Ah right, that's what I was thinking of. My bad, thanks :)

Share this post


Link to post
Share on other sites
Multiply inherited objects have multiple addresses, indeed (well, sort of). However, it doesn't mean that the size of the pointer grows, or that you need to keep track of multiple addresses. Here's the idea. Let's have a class C which inherits from classes A and B, i.e. class C : public A, public B. Let Base be the base address of an instantiated object of class C. Assuming the compiler places the sub-objects(*) in order, object A will also share the same Base address. Object B will be placed at Base + sizeof (A). How can object C and sub-object A share the same address? Pretty simple, object C is aware of the sub-objects it contains. When accessing functions, it can choose the correct v-table (or the correct part of the v-table if one sees this as one big v-table). Let's now cast a C* pointer to a B* pointer. Since object B is unaware of C's v-table, the compiler needs to change the address when casting, so the correct v-table is chosen when invoking functions. How this is to be achieved is known at compile time. All you need to do is stay away from reinterpret_cast, because it won't bother to switch the address for you.

--
* Possibly an incorrect term. I refer to the objects of classes A and B, which the object of class C inherits.

Share this post


Link to post
Share on other sites
Everything you just said, Cybernator, is implementation-defined. I've heard that some implementations represent virtual functions as function objects, rather than with a vtable.

Just something to keep in mind.

Share this post


Link to post
Share on other sites
@Oluseyi: True, but the point was just to give an idea why it's not necessary to "enlarge" the pointer, so I took the liberty to base the rant with a particular implementation in mind. To all C++-standard lawyers, I apologize if this was offending or something.

Share this post


Link to post
Share on other sites
Quote:
Original post by Cybernator
To all C++-standard lawyers, I apologize if this was offending or something.


Heh, I like that phrase. Almost as good as when someone called SiCrane a "C++ athlete".

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!