Allegro.cc - Online Community

Allegro.cc Forums » Off-Topic Ordeals » Function definitions in .h or .cpp files?

This thread is locked; no one can reply to it. rss feed Print
Function definitions in .h or .cpp files?
Bob Keane
Member #7,342
June 2006

While reading up on c++ programming, I found a programming problem which specified putting a function definition in a .cpp file. I remember a previous chapter specified putting the definitions in a .h file, so I was wondering: What is the difference between using a .cpp file as opposed to a .h file for function definitions? Is one preferred over the other? Are there any advantages/disadvantages?

By reading this sig, I, the reader, agree to render my soul to Bob Keane. I, the reader, understand this is a legally binding contract and freely render my soul.
"Love thy neighbor as much as you love yourself means be nice to the people next door. Everyone else can go to hell. Missy Cooper.
The advantage to learning something on your own is that there is no one there to tell you something can't be done.

gnolam
Member #2,030
March 2002
avatar

Function declarations go in the header, function definitions (of which there must never be more than one for each unique function) go in the .cpp file. Never confuse the two.

--
Move to the Democratic People's Republic of Vivendi Universal (formerly known as Sweden) - officially democracy- and privacy-free since 2008-06-18!

bamccaig
Member #7,536
July 2006
avatar

Declaration:

void f(void);

Definition:

void f(void)
{
    std::cout << std::endl;
}

Definitions always go in source files (i.e., .c, .cpp). Declarations for things you want exposed to the "world" go in header files (i.e, .h, .hpp) so that they can be declared to the world by #include'ing them. The declaration says something exists. The definition says what that something is. The definition is used to generate the appropriate assembly. The declaration is used to tell parts that don't yet know about the definition[1] that something will exist when the linking happens. The linker ties the definition to the calls. The compiler only cares that something is declared, but the linker requires things to be defined.

References

  1. The definition can only happen once and each source file is compiled separately, meaning that in order to use code from other files, you need declarations to tell the compiler they exist.
Bob Keane
Member #7,342
June 2006

I understand putting the declarations in a separate file, but does it make a difference whether the definitions are in a .cpp or .h file? I was able to compile and run a program with the definitions in a .h file. Is it just semantics?

Gnolam said:

function definitions (of which there must never be more than one for each unique function)

What about operator overloading, or am I talking apples to oranges?

By reading this sig, I, the reader, agree to render my soul to Bob Keane. I, the reader, understand this is a legally binding contract and freely render my soul.
"Love thy neighbor as much as you love yourself means be nice to the people next door. Everyone else can go to hell. Missy Cooper.
The advantage to learning something on your own is that there is no one there to tell you something can't be done.

Tobias Dammers
Member #2,604
August 2002
avatar

Bob Keane said:

What about operator overloading, or am I talking apples to oranges?

Functions in the sense discussed here are individual overloads for a function name. In other words, a function is identified by its full signature, not just the name. In the following example, four functions are declared, all by the name 'foo':

class Bar {
  void foo();
  void foo() const;
}

void foo(const Bar& the_bar);
int foo(const Bar& bar_one, const Bar& bar_two);

As far as the compiler is concerned, those are four different functions.

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

bamccaig
Member #7,536
July 2006
avatar

Bob Keane said:

I understand putting the declarations in a separate file, but does it make a difference whether the definitions are in a .cpp or .h file? I was able to compile and run a program with the definitions in a .h file. Is it just semantics?

The preprocessor generates a complete source file by reading in the original source file and processing each directive (lines whose first non-whitespace character is #). The #include directive essentially searches the include path for a matching file and inserts the contents in place of the directive. It would be equivalent for you to just copy/paste the header file in place of the #include directive.

Each source file is compiled separately. The linker puts it all together in the end. Definitions can only exist one time for an entire program (the linker needs one and only one definition of everything). The whole point of header files is to allow them to be included in multiple source files during compilation so that source files can know about and use code from other files. In other words, definitions should never (Edit: evidently, inline functions are an exception; one I'm clearly unfamiliar with) go in header files, but there's nothing intelligently enforcing that it can't be done.

The compiler doesn't even know about header files[1]. Header files are dealt with by the preprocessor. The compiler just takes the source code of a single file after being preprocessed and compiles it.

bad.hpp#SelectExpand
1#ifndef BAD_HPP 2 #define BAD_HPP 3 4 #include <iostream> 5
6void f1(void)
7{
8 std::cout << std::endl;
9}
10 11#endif

main.cpp#SelectExpand
1#include <bad.hpp> 2 3int main(int argc, char * argv[]) 4{ 5 f1(); 6 7 return 0; 8}

The above works because bad.hpp is only ever included once so f1 will only ever be defined once. What the compiler actually sees is something like this:

main.cpp#SelectExpand
1void f1(void) 2{ 3 std::cout << std::endl; 4} 5 6int main(int argc, char * argv[]) 7{ 8 f1(); 9 10 return 0; 11}

(For simplicity, I've excluded the declarations that would have come from the standard header files... If you want to see this in action though, pass the -E option to GCC)

However, if the program had another part to it, that might not be the case. Imagine we had two extra files:

good.hpp#SelectExpand
1#ifndef GOOD_HPP 2 #define GOOD_HPP 3 4 #include <bad.hpp> 5 #include <string> 6 7void f2(const std::string); 8 9#endif

good.cpp#SelectExpand
1#include <good.hpp> 2 3void f2(const std::string) 4{ 5 f1(); 6}

This won't work anymore. The reason is, when main.cpp is compiled, a definition for f1 is found (which was inserted by the preprocessor from bad.hpp). Then, when good.cpp is compiled, a definition for f1 is found (again, inserted by the preprocessor from bad.hpp). The compiler is only looking at one source file at a time so the compilation goes fine. However, when the linker tries to put it all together, it finds multiple definitions of f1(void) and returns an error.

References

  1. Some compilers have built-in preprocessors, but the actual compilation routines don't know about header files.
Thomas Fjellstrom
Member #476
June 2000
avatar

You CAN put functions in headers, but it may cause multiple redefinition warnings if you include the header in more than one source file.

The COMMON use of functions in headers are inline functions or methods.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

ReyBrujo
Moderator
January 2001
avatar

Bob Keane said:

I understand putting the declarations in a separate file, but does it make a difference whether the definitions are in a .cpp or .h file?

Also, if you use build systems like makefile, they are able to create a dependency tree to know if a file must be compiled. If you place code in the header, whenever you need to change the code of the function you need to recompile all the files that are using the header. However, if you place the definition in the source file and the declaration in the header, only the source file needs to be recompiled.

When you have a small project it is not much of a difference. But at work projects with over 10,000 objects require 30-45 minutes to compile (including 15 of linking).

--
RB
光子「あたしただ…奪う側に回ろうと思っただけよ」
Mitsuko's last words, Battle Royale

gnolam
Member #2,030
March 2002
avatar

The COMMON use

When it comes to programming rules like one (e.g. "Declarations always go in header files, definitions always go in source files"), the law to abide by is simple: If you don't know exactly what the exceptions to the rule are, follow the rule to the letter like it had no exceptions.

--
Move to the Democratic People's Republic of Vivendi Universal (formerly known as Sweden) - officially democracy- and privacy-free since 2008-06-18!

Bob Keane
Member #7,342
June 2006

I was able to compile and run a program that has a function definition separate from the main.cpp without #including it. I am using an ide btw. The definition file was in the same directory as main.cpp. How does that work, does the compiler compile all .cpp files in the project and the linker link them automatically?

By reading this sig, I, the reader, agree to render my soul to Bob Keane. I, the reader, understand this is a legally binding contract and freely render my soul.
"Love thy neighbor as much as you love yourself means be nice to the people next door. Everyone else can go to hell. Missy Cooper.
The advantage to learning something on your own is that there is no one there to tell you something can't be done.

Thomas Fjellstrom
Member #476
June 2000
avatar

Bob Keane said:

How does that work, does the compiler compile all .cpp files in the project and the linker link them automatically?

If you added the cpp files to your project the IDE will compile them all, and link them together.

Quote:

I was able to compile and run a program that has a function definition separate from the main.cpp without #including it.

As long as you declare a function before using it, you won't have any problems.

If you DON'T pre declare the function in some header or in each source file that uses it (which is the same thing as including a header with the declaration), the compiler may get things wrong. In fact it probably will, unless its a function that returns void, and takes unknown arguments.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

LennyLen
Member #5,313
December 2004
avatar

Bob Keane said:

I was able to compile and run a program that has a function definition separate from the main.cpp without #including it. I am using an ide btw. The definition file was in the same directory as main.cpp. How does that work, does the compiler compile all .cpp files in the project and the linker link them automatically?

Was the definition in a .h file or a .cpp file? If the latter, was that .cpp file in your project? With every IDE I've ever used, all .cpp (or .c) files in the project will always be compiled and linked.

ImLeftFooted
Member #3,935
October 2003
avatar

I put all my function definitions in .cpp files and implementation in .h files. I only include .cpp files and I compile the .h files. Gcc gets a little funny so you have to explicit set the language when you're compiling.

Files:
main.h -> this includes myclass.cpp
myclass.h -> this includes myclass.cpp
myclass.cpp

g++ -x c++ *.h -o mygame.exe

The fact that gcc does not support this natively indicates a dire need for better standards relating to header files and their usage.

Bob Keane
Member #7,342
June 2006

LennyLen said:

Was the definition in a .h file or a .cpp file?

The definition was in a separate .cpp file. The file was saved in the same folder as main.cpp.

LennyLen said:

With every IDE I've ever used, all .cpp (or .c) files in the project will always be compiled and linked.

So the ide assumes all .cpp files in the working directory are part of the project? Wouldn't that cause a problem with stray files? For example, if I copied a folder to create a new project and forgot to delete a .cpp file?

By reading this sig, I, the reader, agree to render my soul to Bob Keane. I, the reader, understand this is a legally binding contract and freely render my soul.
"Love thy neighbor as much as you love yourself means be nice to the people next door. Everyone else can go to hell. Missy Cooper.
The advantage to learning something on your own is that there is no one there to tell you something can't be done.

LennyLen
Member #5,313
December 2004
avatar

Bob Keane said:

So the ide assumes all .cpp files in the working directory are part of the project?

It shouldn't. It should only compile/link files that you've added to the project.

Which IDE are you using?

decepto
Member #7,102
April 2006
avatar

Bob Keane said:

What about operator overloading, or am I talking apples to oranges?

I'm going to be bold here. There's never any good reason to use operator overloading.

--------------------------------------------------
Boom!

LennyLen
Member #5,313
December 2004
avatar

decepto said:

I'm going to be bold here. There's never any good reason to use operator overloading.

That is fairly bold. I've always thought that the way + is overloaded for strings was a good use. name = "Jack" + " " + "Smith";
makes more sense than either:
sprintf(name, "%s %s", "Jack", "Smith");
or

strcat(name, "Jack");
strcat(name, " ");
strcat(name, "Smith");

bamccaig
Member #7,536
July 2006
avatar

Operator overloading is very reasonable. Consider the amount of time it takes for a human to interpret...

a = b + c * d / e % f;

...versus...

a = b.add(c.mult(d).div(e).mod(f));

Operators hopefully make code compact without losing meaning (like using abbreviations or slang). I've actually recently been contemplating a language that supported custom keywords, albeit there are drawbacks to consider and solve first (name collisions perhaps being the most obvious). Operator overloading doesn't suffer from that though. The only potential flaw is misuse, but that can be true of anything (i.e., an add method that actually just prints to stdout).

Tobias Dammers
Member #2,604
August 2002
avatar

Bob Keane said:

I was able to compile and run a program that has a function definition separate from the main.cpp without #including it. I am using an ide btw. The definition file was in the same directory as main.cpp. How does that work, does the compiler compile all .cpp files in the project and the linker link them automatically?

The compiler itself compiles exactly what you tell it to. Taking gcc as an example, the following command:
gcc -c foo.c bar.c main.c
performs the compilation step (-c) for the files foo.c, bar.c, and main.c, outputting corresponding object files (foo.o, bar.o, main.o). It ignores all other files.
An IDE typically adds all source files you create to the project automatically, because that's usually what you want; so if you created the file in an IDE, then yes, the compiler will be instructed to compile it and the linker will include it in the resulting executable.

If you don't #include the header, the compiler will not know the declarations of the functions inside it. However, some compilers may guess when they encounter something they don't know (this is called 'implicit declaration'). When an unknown identifier is used as a function, it is assumed to be called correctly (i.e. with the correct argument structure), and return an int. Similarly, undefined variables are assumed to be ints (in plain C at least).
Proper compiler settings will produce a warning or an error though, as this is not desirable behaviour.

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

gnolam
Member #2,030
March 2002
avatar

When an unknown identifier is used as a function, it is assumed to be called correctly (i.e. with the correct argument structure), and return an int. Similarly, undefined variables are assumed to be ints (in plain C at least).

Thankfully, implicit int was removed completely in C99.

--
Move to the Democratic People's Republic of Vivendi Universal (formerly known as Sweden) - officially democracy- and privacy-free since 2008-06-18!

Tobias Dammers
Member #2,604
August 2002
avatar

I should have added that anyone who knowingly uses this brain-damaged behaviour should be punished. Hard.

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

Go to: