Bien, un ejemplo simple.
Tenemos el siguiente programa:
main.cpp:
- Código: Seleccionar todo
- // Incluye el prototipo de la función imprimeMensaje
 #include "util.h"
 #include <cstdio>
 
 int main() {
 imprimeMensaje();
 
 return 0;
 }
 
A primera vista no vemos el código de la función 
imprimeMensaje, la cual está implementada en otro archivo: 
util.cpp. ¿Por qué es posible llamarla en 
main.cpp? Porque ya contamos con su prototipo declarado en 
util.h:
util.h:
- Código: Seleccionar todo
- #ifndef UTIL_H
 
 #include <cstdio>
 
 void imprimeMensaje( void );
 
 #endif // UTIL_H
 
En 
util.h sólo se tiene la declaración de la función 
imprimeMensaje, al incluir este archivo en 
main.cpp es posible utilizar dicha función y compilar.
Sin embargo, aún necesitamos la implementación de la función:
util.cpp:
- Código: Seleccionar todo
- #include "util.h"
 
 // Implementación de imprimeMensaje
 void imprimeMensaje( void ) {
 printf( "Hola :)\n" );
 }
 
Pasos para compilación:$ g++ -c util.cpp
$ g++ -c main.cpp
Para crear el ejecutable (enlazar):
$ g++ -o nombre-ejecutable main.o util.o
La opción 
-c indica que no enlazaremos, sólo compilaremos. Una vez compilados util.cpp y main.cpp tendremos los archivos de código objeto util.o y main.o, los cuales utilizamos para construir finalmente el ejecutable, pasamos la opción -o para indicar el nombre del archivo de salida, seguido de los archivos de código objeto necesarios para construirlo.
Finalmente ejecutamos:
$ ./nombre-ejecutable
Suerte 

.