When we design classes in Java, Vala, or C# we put the definition and declaration in the same source file. But in C++ it is traditionally preferred to separate the definition and declaration in two or more files.
What happens if I just use a header file and put everything into it, like Java? Is there a performance penalty or something?
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.
Yes, that is correct. The function will be defined in every place where you include its header. The compiler will care about putting only one instance of it into the resulting program, by eliminating the others.
The header file contains only declarations, and is included by the . c file for the module. Put only structure type declarations, function prototypes, and global variable extern declarations, in the . h file; put the function definitions and global variable definitions and initializations in the .
Header files are needed to declare functions and variables that are available. You might not have access to the definitions (=the . c files) at all; C supports binary-only distribution of code in libraries.
The answer depends on what kind of class you're creating.
C++'s compilation model dates back to the days of C, and so its method of importing data from one source file into another is comparatively primitive. The #include
directive literally copies the contents of the file you're including into the source file, then treats the result as though it was the file you had written all along. You need to be careful about this because of a C++ policy called the one definition rule (ODR) which states, unsurprisingly, that every function and class should have at most one definition. This means that if you declare a class somewhere, all of that class's member functions should be either not defined at all or defined exactly once in exactly one file. There are some exceptions (I'll get to them in a minute), but for now just treat this rule as if it's a hard-and-fast, no-exceptions rule.
If you take a non-template class and put both the class definition and the implementation into a header file, you might run into trouble with the one definition rule. In particular, suppose that I have two different .cpp files that I compile, both of which #include
your header containing both the implementation and the interface. In this case, if I try linking those two files together, the linker will find that each one contains a copy of the implementation code for the class's member functions. At this point, the linker will report an error because you have violated the one definition rule: there are two different implementations of all the class's member functions.
To prevent this, C++ programmers typically split classes up into a header file which contains the class declaration, along with the declarations of its member functions, without the implementations of those functions. The implementations are then put into a separate .cpp file which can be compiled and linked separately. This allows your code to avoid running into trouble with the ODR. Here's how. First, whenever you #include
the class header file into multiple different .cpp files, each of them just gets a copy of the declarations of the member functions, not their definitions, and so none of your class's clients will end up with the definitions. This means that any number of clients can #include
your header file without running into trouble at link-time. Since your own .cpp file with the implementation is the sole file that contains the implementations of the member functions, at link time you can merge it with any number of other client object files without a hassle. This is the main reason that you split the .h and .cpp files apart.
Of course, the ODR has a few exceptions. The first of these comes up with template functions and classes. The ODR explicitly states that you can have multiple different definitions for the same template class or function, provided that they're all equivalent. This is primarily to make it easier to compile templates - each C++ file can instantiate the same template without colliding with any other files. For this reason, and a few other technical reasons, class templates tend to just have a .h file without a matching .cpp file. Any number of clients can #include
the file without trouble.
The other major exception to the ODR involves inline functions. The spec specifically states that the ODR does not apply to inline functions, so if you have a header file with an implementation of a class member function that's marked inline, that's perfectly fine. Any number of files can #include
this file without breaking the ODR. Interestingly, any member function that's declared and defined in the body of a class is implicitly inline, so if you have a header like this:
#ifndef Include_Guard #define Include_Guard class MyClass { public: void DoSomething() { /* ... code goes here ... */ } }; #endif
Then you're not risking breaking the ODR. If you rewrite this as
#ifndef Include_Guard #define Include_Guard class MyClass { public: void DoSomething(); }; void MyClass::DoSomething() { /* ... code goes here ... */ } #endif
then you would be breaking the ODR, since the member function isn't marked inline and if multiple clients #include
this file there will be multiple definitions of MyClass::DoSomething
.
So to summarize - you should probably split up your classes into a .h/.cpp pair to avoid breaking the ODR. However, if you're writing a class template, you don't need the .cpp file (and probably shouldn't have one at all), and if you're okay marking every single member function of your class inline you can also avoid the .cpp file.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With