El C++ FAQ es un excelente recurso sobre todas las idiosincrasias de C++, pero es probablemente un poco más avanzado de lo que busca: la mayoría de las preguntas (no solo las respuestas) son misterios incluso para desarrolladores bastante experimentados de C++ .
Creo que si buscas en Google tutoriales en C++, podrás encontrar algo. También es posible que desee intentar aprender el lenguaje ensamblador (o al menos obtener una introducción rápida sobre cómo realmente suceden las cosas en un microprocesador), ya que tanto C como C++ están bastante cerca del hardware en la forma en que hacen las cosas. De ahí viene su velocidad y poder, pero tiene el precio de algunas de las mejores abstracciones que Java ofrece.
Puedo intentar responder a sus preguntas específicas, pero no sé qué tan bien lo haré.
Una de las claves para entender la relación entre los archivos de encabezado y los archivos cpp es comprender la idea de una "unidad de traducción". Un archivo de clase Java puede considerarse una unidad de traducción, ya que es la unidad básica compilada en forma binaria. En C++, casi todos los archivos cpp son unidades de traducción (existen excepciones si haces cosas raras).
Un archivo de encabezado se puede incluir en varias unidades de traducción (y se debe incluir en todas partes que usa lo que se define en el encabezado). La directiva #include literalmente solo hace una sustitución de texto: el contenido del archivo incluido se inserta textualmente donde está la directiva #include. Normalmente desea que su interfaz de clase esté definida en el archivo de encabezado y la implementación en el archivo cpp. Esto se debe a que no desea exponer sus detalles de implementación a otras unidades de traducción que pueden incluir el encabezado. En C++, todo, incluidas las clases, no son realmente objetos ricos, sino fragmentos de memoria a los que el compilador asigna significado ... compilando la misma información de encabezado en cada unidad de traducción, el compilador garantiza que todas las unidades de traducción tengan el la misma comprensión de lo que representa un pedazo de memoria. Debido a la falta de datos abundantes después del tiempo de compilación, cosas como la reflexión son imposibles.El segundo paso en el proceso de compilación de C++ es vincular, que es donde el enlazador toma todas las unidades de traducción compiladas y busca símbolos (generalmente llamadas de función, pero también variables) utilizados en una unidad de traducción pero no definidos allí. Luego busca otra unidad de traducción que defina ese símbolo y "los vincule", de modo que todas las llamadas a una función en particular se dirijan a la unidad de traducción que lo define.
En el caso de los métodos de clase, deben llamarse a través de una instancia de clase, que está detrás de las escenas solo como un puntero a una parte de la memoria. Cuando el compilador ve este tipo de llamadas a métodos, emite un código que llama a una función, pasando implícitamente el puntero, conocido como puntero this
, a la función como primer argumento. Puede tener funciones que no pertenecen a las clases (no a los métodos, como dijo, porque un método es propiamente una función miembro de una clase y, por lo tanto, no puede existir sin una clase) porque el vinculador no tiene ningún concepto de una clase. Verá una unidad de traducción que define una función y otra que llama a una función y las une.
Eso terminó siendo mucho más largo de lo que esperaba, y por supuesto es una simplificación excesiva, pero es preciso según mi conocimiento y el nivel de detalle proporcionado ... espero que ayude a algunos. Al menos debería darle un punto de partida para algunos googlear.
Editar: Gracias a todos los que respondieron, todas las respuestas fueron útiles e informativas. – Whatsit
Para cualquier persona que se encuentre en una situación similar, he encontrado esta página muy útil, en particular la sección A3.3 (Clases): http://www.horstmann.com/ccj2/ccjapp3.html – Whatsit