Search

8.9 — Class code and header files

Defining member functions outside the class definition

All of the classes that we have written so far have been simple enough that we have been able to implement the member functions directly inside the class definition itself. For example, here’s our ubiquitous Date class:

However, as classes get longer and more complicated, having all the member function definitions inside the class can make the class harder to manage and work with. Using an already-written class only requires understanding its public interface (the public member functions), not how the class works underneath the hood. The member function implementation details just get in the way.

Fortunately, C++ provides a way to separate the “declaration” portion of the class from the “implementation” portion. This is done by defining the class member functions outside of the class definition. To do so, simply define the member functions of the class as if they were normal functions, but prefix the class name to the function using the scope resolution operator (::) (same as for a namespace).

Here is our Date class with the Date constructor and setDate() function defined outside of the class definition. Note that the prototypes for these functions still exist inside the class definition, but the actual implementation has been moved outside:

This is pretty straightforward. Because access functions are often only one line, they are typically left in the class definition, even though they could be moved outside.

Here is another example that includes an externally defined constructor with a member initialization list:

becomes:

Putting class definitions in a header file

In the lesson on header files, you learned that you can put function declarations inside header files in order to use those functions in multiple files or even multiple projects. Classes are no different. Class definitions can be put in header files in order to facilitate reuse in multiple files or multiple projects. Traditionally, the class definition is put in a header file of the same name as the class, and the member functions defined outside of the class are put in a .cpp file of the same name as the class.

Here’s our Date class again, broken into a .cpp and .h file:

Date.h:

Date.cpp:

Now any other header or code file that wants to use the Date class can simply #include "Date.h". Note that Date.cpp also needs to be compiled into any project that uses Date.h so the linker knows how Date is implemented.

Doesn’t defining a class in a header file violate the one-definition rule?

It shouldn’t. If your header file has proper header guards, it shouldn’t be possible to include the class definition more than once into the same file.

Types (which include classes), are exempt from the part of the one-definition rule that says you can only have one definition per program. Therefore, there isn’t an issue #including class definitions into multiple code files (if there was, classes wouldn’t be of much use).

Doesn’t defining member functions in the header violate the one-definition rule?

It depends. Member functions defined inside the class definition are considered implicitly inline. Inline functions are exempt from the one definition per program part of the one-definition rule. This means there is no problem defining trivial member functions (such as access functions) inside the class definition itself.

Member functions defined outside the class definition are treated like normal functions, and are subject to the one definition per program part of the one-definition rule. Therefore, those functions should be defined in a code file, not inside the header. The one exception for this is for template functions, which we’ll cover in a future chapter.

So what should I define in the header file vs the cpp file, and what inside the class definition vs outside?

You might be tempted to put all of your member function definitions into the header file, inside the class. While this will compile, there are a couple of downsides to doing so. First, as mentioned above, this clutters up your class definition. Second, if you change anything about the code in the header, then you’ll need to recompile every file that includes that header. This can have a ripple effect, where one minor change causes the entire program to need to recompile (which can be slow). If you change the code in a .cpp file, only that .cpp file needs to be recompiled!

Therefore, we recommend the following:

  • For classes used in only one file that aren’t generally reusable, define them directly in the single .cpp file they’re used in.
  • For classes used in multiple files, or intended for general reuse, define them in a .h file that has the same name as the class.
  • Trivial member functions (trivial constructors or destructors, access functions, etc…) can be defined inside the class.
  • Non-trivial member functions should be defined in a .cpp file that has the same name as the class.

In future lessons, most of our classes will be defined in the .cpp file, with all the functions implemented directly in the class definition. This is just for convenience and to keep the examples short. In real projects, it is much more common for classes to be put in their own code and header files, and you should get used to doing so.

Default parameters

Default parameters for member functions should be declared in the class definition (in the header file), where they can be seen by whomever #includes the header.

Libraries

Separating the class definition and class implementation is very common for libraries that you can use to extend your program. Throughout your programs, you’ve #included headers that belong to the standard library, such as iostream, string, vector, array, and other. Notice that you haven’t needed to add iostream.cpp, string.cpp, vector.cpp, or array.cpp into your projects. Your program needs the declarations from the header files in order for the compiler to validate you’re writing programs that are syntactically correct. However, the implementations for the classes that belong to the C++ standard library are contained in a precompiled file that is linked in at the link stage. You never see the code.

Outside of some open source software (where both .h and .cpp files are provided), most 3rd party libraries provide only header files, along with a precompiled library file. There are several reasons for this: 1) It’s faster to link a precompiled library than to recompile it every time you need it, 2) a single copy of a precompiled library can be shared by many applications, whereas compiled code gets compiled into every executable that uses it (inflating file sizes), and 3) intellectual property reasons (you don’t want people stealing your code).

Having your own files separated into declaration (header) and implementation (code file) is not only good form, it also makes creating your own custom libraries easier. Creating your own libraries is beyond the scope of these tutorials, but separating your declaration and implementation is a prerequisite to doing so.


8.10 -- Const class objects and member functions
Index
8.8 -- The hidden “this” pointer

173 comments to 8.9 — Class code and header files

  • stalker0718

    C++ Standard Library, The: A Tutorial and Reference 2nd Edition
    is this book still relevant for stl ?
    been published in 2012

    • nascardriver

      There's probably a lot of useful information in there, but take it with many grains of salt. There have been additions and changes to the language since C++11 and the things that are described in the book might no longer be true.

  • srt1104

    "declaration" and "definition" in regard to classes was used interchangeably in this section.
    Can you explain the difference between the two? If whatever we code in .cpp file is "implementation", then what is the code in .h file called?

    • nascardriver

      Inside the class, normal rules for declaration and definition apply

      Most often, classes are defined in a header and their member functions are only declared in the class definition. The member functions are then defined in a source file.

  • Tony Kolarek

    Hi nascar (once again....)

    At this point, I am confused again.

    Perhaps it's not an 'update' error like in the previous chapter. But why are we once again calling the function inside the constructor? I don't see the difference between doing so, and just using a member initializer list. I've read in a previous chapter that this method can be used eg. when we want to reset our members, but other than that, I see no clear usage of calling our member functions in the constructor.

    Coud you please help me understand that? Thank you a lot.

    • nascardriver

      If `setDate` will always remain the same as it is, the constructor should initialize the members in the member initializer list.

      But there are reasons why `setDate` might change, eg. to overflow into month when `day > 31`. By calling `setDate` from the constructor, that behavior would also apply to the constructor, which is desirable.

  • Alek

    hey,I have a few questions here :I really don't know what the difference is between .cpp and .
    Let's say I define my class and put member functions delcaration there but instead of creating a .cpp file for definitions I create another .h file and do it there.Can't this be done ? if yes why shouldn't we do this ?
       2:"the implementations for the classes that belong to the C++ standard library are contained in a precompiled file that is linked in at the link stage. You never see the code." how is this done ? can we do the same with our own classes?.and one thing else,when I want to create an object of the class I have declared and defined in separate .h and .cpp file,ilcuding the .cpp file in another file such as main.cpp is enough or I have to include both of them ?

    thanks in advance!

    • nascardriver

      Headers files get copied and compiled as a part of every source file that includes them. If you include the header in 20 source files, it will get compiled 20 times. That's slow. On top of that, your header will probably need extra includes to hold the definitions. Those includes get copied and compiled multiple times too and might cause collisions with names from other files.
      Do as much as possible in cpp files, and as few as possible in headers.

      You can compile your project as a library. This produces a .lib, .a, .so, .dylib or so file depending on your platform. To use the library in another project, you only need that .lib etc. file and the headers. Users of the library don't see the definitions if you placed them in source files.

      Never include cpp files. You include header files. The compiler is happy with declarations alone. It compiles main.cpp (Which included class.h) and class.cpp separately (These files don't know about each other). The linker later connects the compiled versions of these 2 source files together.

      • Alek

        hello again, by the way I tried to include .cpp file into main and I couldn't.(#include "something.cpp"),I couldn't do it in this way.
        Thanks for your answer.

  • Zuhail

    Hey there, I've been very confused in trying to figure out the difference between
    Class declaration VS Class definition , care to comment please?
    P.S. 'Class definition' shouldn't make sense because isn't it just a blueprint for user-defined type and it doesn't allocate any memory not until we define an object of our class type thus shouldn't there be only the term 'Class declaration' ?

    • nascardriver

      The memory allocation aspect of "definition" is only valid for variables, not for types.

      Inside the class, there can again be declaration and definitions. These follow the same rules as if they were outside of the class

Leave a Comment

Put all code inside code tags: [code]your code here[/code]