Jump to content
  • Advertisement
ryt

C++ Translation unit and classes

Recommended Posts

As I'm reading C++ Programming Language and some other tutorials I came on Translation Unit part. I got a bit confused how they work with classes. What is rally not clear to me is inclusion of class headers in different other files that need them. Somewhere in these tutorials I red that each time when we #include a class header, that the current translation unit has its own class. From that I understood that even if we use include guards, that different files, that include same classes, have their own definitions of classes.

So for e.g. let's say that we have two classes A and B. Another two separate files Alpha and Beta, where they include both classes. A third file main.cpp that includes Alpha and Beta, but knows nothing of A and B.
From what I understood is that in main.cpp we will have two definitions of A and two of B, even if A and B use include guards.

Is this true or I confused something?

Share this post


Link to post
Share on other sites
Advertisement
Posted (edited)

You are pretty close, actually! What makes this work is that the header just contains the declaration of the class, not it's actual implementation. All the compiler sees is the promise that there is a class named A with the following functions and it can include references to these functions. The actual implementation file, Alpha or Beta in your case, only contain references to the class and it's functions but not it's actual code. That would come from the .cpp file. It's up to the linker at the end to merge the compiled code for the class itself with the references from Alpha and Beta.

It's different if the code is directly included in the header file for the classes. If they are not templated and not inlined, the linker will actually complain about multiple definitions of the same function existing in both Alpha and Beta. That's because each translation unit actually did emit code for the class. When inlining, there is no actual function generated and instead the code of the function is directly emitted in the callsite, so no duplicate functions here. Lastly, templates: The compiler has to see the full definition when instantiating a template, so if Alpha and Beta both include class A and instantiate it as A<int>, they will both generate the same code for A<int>. In this case however, the linker will not complain about duplicate implementations of A<int> and instead just squash both of them down into one so that both Alpha and Beta reference the one canonical implementation of A<int>.

Edited by JustSid

Share this post


Link to post
Share on other sites
3 hours ago, ryt said:

From what I understood is that in main.cpp we will have two definitions of A and two of B, even if A and B use include guards.

Using include guards in declaration files (.h files) guarantees that multiple declarations of the same class will not appear in any translation units.

Also, the definitions of A and B are in their own .cpp files and do not appear in the translation unit for main.cpp. I think in the quoted text you have miswrote definition for declaration.

Share this post


Link to post
Share on other sites

Multiple class declarations are allowed in one translate unit. So it's fine you include class A many times in one .cpp.

But class definition (which define the function code, etc) must be in a single translate unit, except they are inline.

Share this post


Link to post
Share on other sites

Trying with different take:

When you use something the compiler needs to know the size and names. 

If you want to say a pointer to something, it needs to know it exists.  If you have a function that takes foo(A* const bar) then the compiler needs to know that A is a thing. The compiler already knows how big a pointer is, but it needs to know that an A is a thing.  

If you're working with actual instances of an object the compiler needs to know how big it is and what data it's got.  If an A is 32 bytes, or 64 bytes, or 256 bytes, or some other size, the compiler needs to know how big it is in order to work with them as objects. If you want to access something inside it the compiler needs to know the name and where the data is at inside the structure.

Inline functions can be part of those descriptions when properly marked so the compiler knows they're not the regular standalone functions.

Header files give those details. 

The compiler allows you to repeat those details as many times as you'd like as long as they're the same every time.  It is generally possible to include files multiple times without being an issue other than longer compile times. 

 

However, when you've got functions that manipulate those objects, the actual implementation of the class's functions that code should only appear once. Those are part of a compilation unit and can only exist in one place. When other compilation units call the functions the linker links up the call with the one-and-only implementation.

Share this post


Link to post
Share on other sites

Multiple declarations of a class are not allowed in a translation unit. It doen't matter if they are exactly alike are not. This is the whole point of include guards.

Share this post


Link to post
Share on other sites

You're allowed unlimited identical declarations with either internal or external linkage, but only one definition.  Most people create a header that is a class definition, but that's not strictly required.

You can be more strict and remove nearly all the implementation details from both the .h and .cpp files, but it's a significant effort.  In large projects with long build times it can help to make occasional passes to do it, but in general it's not done.

Share this post


Link to post
Share on other sites
Posted (edited)
2 hours ago, frob said:

You're allowed unlimited identical declarations with either internal or external linkage, but only one definition.  Most people create a header that is a class definition, but that's not strictly required.

You can be more strict and remove nearly all the implementation details from both the .h and .cpp files, but it's a significant effort.  In large projects with long build times it can help to make occasional passes to do it, but in general it's not done.

Please tell me what you think the purpose of include guards are in header files if there is no problem with multiple declarations of the same class in a translation unit.

Edited by fleabay

Share this post


Link to post
Share on other sites
2 hours ago, fleabay said:

Please tell me what you think the purpose of include guards are in header files if there is no problem with multiple declarations of the same class in a translation unit.

I did. Again, note the difference between declaration and definition.

4 hours ago, frob said:

Most people create a header that is a class definition, but that's not strictly required.

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement
×

Important Information

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

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!