Pregunta

Muchos lenguajes, como Java, C #, no hacen declaración independiente de la aplicación. C # tiene un concepto de clase parcial, pero la implementación y la declaración aún permanecen en el mismo archivo.

¿Por qué no lo hace C ++ tiene el mismo modelo? ¿Es más práctico tener los archivos de cabecera?

Me refiero a las versiones actuales y futuras de C ++ estándar.

¿Fue útil?

Solución

Yo habitualmente un tirón entre C # y C ++, y la falta de archivos de cabecera en C # es una de mis mayores manías. Puedo mirar a un fichero de cabecera y aprender todo lo que necesita saber acerca de una clase - lo que es las funciones miembro son llamados, su sintaxis llamada, etc -. Sin tener que vadear a través de páginas del código que implementa la clase

Y sí, sé de las clases parciales y #regions, pero no es lo mismo. Las clases parciales en realidad empeorar el problema, ya que una definición de clase se reparte entre varios archivos. En lo que #regions van, parece que nunca se ampliará en la forma que me gustaría que lo que estoy haciendo en este momento, así que tengo que pasar tiempo en expansión de los poco más hasta que llegue el punto de vista correcto.

Tal vez si IntelliSense de Visual Studio funcionó mejor para C ++, no tendría una razón de peso a tener que hacer referencia a archivos .h tan a menudo, pero incluso en VS2008, C ++ 'intelisense s no puedo tocar C #' s

Otros consejos

Compatibilidad hacia atrás - Los archivos de cabecera no se eliminan, ya que rompería Compatibilidad hacia atrás

.

Los archivos de cabecera permiten la compilación independiente. No es necesario para acceder o incluso tener los archivos de implementación para compilar un archivo. Esto puede hacer más fácil para los distribuida construye.

Esto también permite que los SDK para hacer un poco más fácil. Puede proporcionar sólo los encabezados y algunas bibliotecas. Hay, por supuesto, formas de evitar esto que utilizan otros idiomas.

Bjarne Stroustrup ha llamado encabezado una chapuza.

Pero sin un formato binario estándar que incluye los metadatos necesarios (como archivos de clase Java, .Net o archivos PE) no veo ninguna manera de implementar la función. Un ELF o a.out binaria despojado no tiene mucha de la información que se necesita para extraer. Y no creo que la información se almacena en archivos de Windows cada vez XCOFF.

El Diseño y Evolución de C ++ , BS da a cabo una de las razones más ...

El mismo archivo de cabecera puede tener dos o más archivos de aplicación que se pueden trabajar-upon simultáneamente por más de un programador sin la necesidad de un sistema de control de código fuente.

Esto puede parecer extraño en estos días, pero supongo que era un tema importante cuando C ++ fue inventado.

C fue hecho para hacer la escritura de un compilador fácilmente. Se hace un montón de cosas sobre la base de que un principio. Punteros sólo existen para hacer la escritura de un compilador más fácil, al igual que archivos de cabecera. Muchas de las cosas heredadas de C ++ se basan en la compatibilidad con estas características implementadas para hacer compilador de escritura más fácil.

Es una buena idea en realidad. Cuando se creó C, C y Unix fue amable de un par. C portado Unix, Unix corrió C. De esta manera, C y Unix podrían propagarse rápidamente de una plataforma a otra mientras que un sistema operativo basado en el montaje tuvo que ser completamente re-escrito para ser portado.

El concepto de especificar una interfaz en un archivo y la aplicación en otro no es una mala idea en absoluto, pero eso no es lo que los archivos de cabecera C son. Son simplemente una manera de limitar el número de pasadas de un compilador tiene que hacer a través de su código fuente y permitir una cierta abstracción limitada del contrato entre archivos para que puedan comunicarse.

Estos elementos, punteros, ficheros de cabecera, etc ... realmente no ofrecen ninguna ventaja sobre otro sistema. Al poner más esfuerzo en el compilador, puede compilar un objeto de referencia con tanta facilidad como un puntero al mismo código objeto exacto. Esto es lo que hace C ++ ahora.

C es un gran, un lenguaje sencillo. Tenía un conjunto de características muy limitado, y se podría escribir un compilador sin mucho esfuerzo. Portarlo es generalmente trivial! No estoy tratando de decir que es una mala lengua ni nada, es sólo que los objetivos primarios de C cuando se creó puede dejar restos en el idioma que son más o menos innecesaria, pero van a ser mantenido en torno a la compatibilidad.


Parece que algunas personas no creen realmente que C fue escrito para el puerto de Unix, por lo que aquí: ( desde )

  

La primera versión de UNIX fue escrito   en lenguaje ensamblador, pero Thompson   la intención era que iba a ser escrito   en un lenguaje de alto nivel.

     

Thompson primero intentó en 1971 para utilizar   Fortran en el PDP-7, pero renunció   después del primer día. Luego escribió una   muy lenguaje sencillo que llamó B,   que se puso en marcha en el PDP-7. Eso   trabajadas, pero hubo problemas.   En primer lugar, debido a que la aplicación fue   interpretado, siempre iba a ser   lento. En segundo lugar, las nociones básicas de B,   que se basaba en la palabra-orientado   BCPL, simplemente no eran las adecuadas para una   máquina orientado a bytes como el nuevo   PDP-11.

     

Ritchie utiliza el PDP-11 para agregar tipos   a B, que durante un tiempo se llamó NB   para "Nuevo B", y luego empezó a   escribir un compilador para él. "De manera que la   primera fase de la C era realmente estos dos   fases en corto sucesión de, primero,   algunos cambios en el lenguaje de B, en realidad,   la adición de la estructura de tipo sin demasiado   mucho cambio en la sintaxis; y haciendo   el compilador ", dijo Ritchie.

     

"La segunda fase fue más lento", dijo   de reescribir UNIX en C. Thompson   se inició en el verano de 1972, pero tuvo   dos problemas: averiguar cómo ejecutar   los co-rutinas básicas, es decir, cómo   cambiar el control de un proceso a   otro; y la dificultad en conseguir   la estructura de datos adecuada, ya que la   versión original de C no tenía   estructuras.

     

"La combinación de las cosas que causó   Ken a renunciar a lo largo del verano,"   dijo Ritchie. "Durante el año, añadí   estructuras y, probablemente, el hecho   código de compilador de algo mejor -   mejor código - y así durante el próximo   verano, que era cuando hicimos la   concertada esfuerzo y realmente hizo rehacer   todo el sistema operativo en C ".


Este es un ejemplo perfecto de lo que quiero decir. De los comentarios:

  

Los punteros sólo existen para hacer la escritura de un compilador más fácil? No. Existen punteros porque son la abstracción más simple posible a través de la idea de indirección. - Adam Rosenfield (una hora)

Tiene usted razón. Con el fin de poner en práctica indirection, los punteros son la abstracción más simple posible implementar. De ninguna manera son el más simple posible de comprender o utilizar. Las matrices son mucho más fácil.

El problema? Para implementar matrices tan eficientemente como punteros hay que añadir más o menos una pila enorme de código a su compilador.

No hay razón por la que no podrían haber diseñado C sin punteros, pero con código como este:

int i=0;
while(src[++i])
    dest[i]=src[i];

se tardará mucho esfuerzo (en la parte compiladores) para factorizar la explícita i + i + src y dest adiciones y hacer que crear el mismo código que esto haría:

while(*(dest++) = *(src++))
    ;

Factoring a cabo esa variable "i" después de los hechos es difícil. Los nuevos compiladores puede hacerlo, pero en aquel entonces no era posible, y el sistema operativo que se ejecuta en el hardware que necesitan poco chungo optimizaciones de esa manera.

Ahora algunos sistemas necesitan ese tipo de optimización (yo trabajo en una de las plataformas más lentos alrededor - cajas de cable set-top, y la mayoría de nuestras cosas es en Java) y en el caso improbable de que que debe de estar, la nuevos compiladores de C deben ser lo suficientemente inteligente como para hacer ese tipo de conversión por sí sola.

Si quieres C ++ sin archivos de cabecera entonces tengo buenas noticias para ti.

ya existe y se llama D ( http://www.digitalmars.com/d/ index.html )

Técnicamente D parece ser mucho mejor que C ++, pero simplemente no es suficiente corriente para su uso en muchas aplicaciones en el momento.

Uno de los objetivos de C ++ s es ser un superconjunto de C, y es difícil para que lo haga si no puede soportar archivos de cabecera. Y, por extensión, si desea los archivos de cabecera especiales que usted puede también tener en cuenta la escisión de CPP (el pre-procesador, no más-plus) en conjunto; C # y Java no especifican preprocesadores macro con sus normas (pero hay que señalar que en algunos casos pueden ser e incluso se utilizan incluso con estas lenguas).

Como C ++ está diseñado en este momento, es necesario prototipos - al igual que en C - para comprobar estáticamente cualquier código compilado que hace referencia a las funciones externas y clases. Sin archivos de cabecera, que tendría que escribir estas definiciones de clases y declaraciones de funciones antes de usarlos. Para C ++ no utilizar los archivos de cabecera, habría que añadir una característica en el idioma que apoyaría algo como palabra clave import de Java. Eso sería una adición importante, y el cambio; para responder a su pregunta de si sería práctico: Yo no lo creo - no en todos

.

Muchas personas son conscientes de las deficiencias de los archivos de cabecera y hay ideas para introducir más potente sistema de módulos en C ++. Es posible que desee echar un vistazo a módulos en C ++ (Revisión 5) por Daveed Vandevoorde.

Bueno, C ++ per se no debe eliminar los archivos de cabecera debido a la compatibilidad hacia atrás. Sin embargo, yo creo que son una idea tonta en general. Si desea distribuir un lib de código cerrado, esta información se puede extraer de forma automática. Si usted quiere entender cómo utilizar una clase w / o mirando la puesta en práctica, eso es lo que son generadores de documentación para, y lo hacen una diablos de mucho mejor un trabajo.

Hay valor en la definición de la interfaz de la clase en un componente separado en el fichero de aplicación.

Se puede hacer con interfaces, pero si vas por ese camino, entonces usted está diciendo implícitamente que las clases son deficientes en términos de la separación de la implementación del contrato.

Modula-2 tenía la idea correcta, módulos y módulos de definición de aplicación. http://www.modula2.org/reference/modules.php

respuesta

Java / C # 's es una aplicación implícita de la misma (aunque orientado a objetos.)

Los archivos de cabecera son una chapuza, porque los archivos de cabecera expresan detalle de implementación (como variables privadas.)

Al pasar a Java y C #, me parece que si un idioma requiere soporte IDE para el desarrollo (por ejemplo, que las interfaces de clase públicos son navegables en los navegadores de clase), entonces este es tal vez una declaración de que el código no se sostiene por su propios méritos como particularmente legible.

Me parece la mezcla de interfaz con el detalle de implementación bastante horrible.

Fundamentalmente, la falta de capacidad de documentar la firma public class en un archivo independiente concisa bien comentado de aplicación me indica que el diseño del lenguaje está escrito por conveniencia de la autoría, más comodidad de mantenimiento. Bueno, yo estoy divagando acerca de Java y C # ahora.

Una ventaja de esta separación es que es fácil de ver sólo la interfaz, sin que requiere un editor avanzado .

Si desea que la razón por la que esto nunca sucederá: se rompería casi todo el software existente C ++. Si nos fijamos en algunos de documentación de diseño comité de C ++, observaron varias alternativas para ver la cantidad de código que se rompería.

Sería mucho más fácil cambiar la sentencia switch en algo medianamente inteligente. Eso sería romper sólo un poco de código. Todavía no va a suceder.

EDITADO PARA LA NUEVA IDEA:

La diferencia entre C ++ y Java que hace que los archivos necesarios encabezado C ++ es que los objetos de C ++ no son necesariamente los punteros. En Java, todas las instancias de la clase se conocen por el puntero, aunque no se ve de esa manera. C ++ tiene objetos asignados en el montón y la pila. Esto significa C ++ necesita una manera de saber qué tan grande será un objeto, y donde los miembros de datos están en la memoria.

No existe ningún idioma sin archivos de cabecera. Es un mito.

Look en cualquier distribución de la biblioteca propietaria para Java (no tengo experiencia en C # para hablar, pero yo esperaría que es lo mismo). Ellos no le dan el archivo fuente completo; que sólo te dan un archivo con la aplicación de todos los métodos de borrado ({} o {return null;} o similares) y todo lo que pueden salirse de ocultar oculto. No se puede llamar cualquier cosa menos que un encabezado.

No hay ninguna razón técnica, sin embargo, por las que un compilador C o C ++ podían contar todo en un archivo marcado apropiadamente como extern a menos que el archivo está siendo compilado directamente. Sin embargo, los costos para la compilación sería inmenso porque ni C ni C ++ es rápido para analizar, y eso es una consideración muy importante. Cualquier método más complejo de cabeceras melding y fuente se encontraría con rapidez los problemas técnicos como la necesidad de que el compilador para conocer la disposición de un objeto.

Los archivos de cabecera son una parte integral de la lengua. Sin archivos de cabecera, todas las bibliotecas estáticas, bibliotecas dinámicas, prácticamente cualquier biblioteca de pre-compilados se vuelve inútil. Los archivos de cabecera también hacen que sea más fácil de documentar todo, y hacen posible mirar por encima de una biblioteca API / del archivo, sin pasarse de cada bit de código.

También hacen que sea más fácil de organizar su programa. Sí, usted tiene que estar constantemente cambiando de fuente a la cabecera, sino que también permiten definir las API internas y privadas dentro de las implementaciones. Por ejemplo:

MySource.h:

extern int my_library_entry_point(int api_to_use, ...);

MySource.c:

int private_function_that_CANNOT_be_public();

int my_library_entry_point(int api_to_use, ...){
  // [...] Do stuff
}

int private_function_that_CANNOT_be_public() {

}

Si #include <MySource.h>, a continuación, se obtiene my_library_entry_point.

Si #include <MySource.c>, entonces también obtener private_function_that_CANNOT_be_public.

¿Ves lo que podría ser una cosa muy mala si has tenido una función para obtener una lista de contraseñas, o una función que implementa el algoritmo de cifrado, o una función que expondría el funcionamiento interno de un sistema operativo, o una función que privilegios hizo caso omiso, etc.

Oh sí!

Después de la codificación en Java y C # es muy molesto tener 2 archivos para cada clase. Así que estaba pensando cómo puedo combinar sin romper el código existente.

De hecho, es muy fácil. Sólo hay que poner la definición (aplicación) en el interior de una sección #ifdef y añadir una definición en la línea de comandos del compilador para compilar ese archivo. Eso es todo.

Aquí es un ejemplo:

/* File ClassA.cpp */

#ifndef _ClassA_
#define _ClassA_

#include "ClassB.cpp"
#include "InterfaceC.cpp"

class ClassA : public InterfaceC
{
public:
    ClassA(void);
    virtual ~ClassA(void);

    virtual void methodC();

private:
    ClassB b;
};

#endif

#ifdef compiling_ClassA

ClassA::ClassA(void)
{
}

ClassA::~ClassA(void)
{
}

void ClassA::methodC()
{
}

#endif

En la línea de comandos, compilar ese archivo con

-D compiling_ClassA

Los demás archivos que necesiten incluir claseA simplemente puede hacer

#include "ClassA.cpp"

Por supuesto, la adición de la definir en la línea de comando puede ser fácilmente añadió con una expansión de macro (Studio compilador Visual) o con un variables automáticas (Agrega GNU) y usando la misma nomenclatura para el nombre de definir.

Todavía no entiendo el punto de algunas declaraciones. La separación de los activos y de aplicación es una cosa muy buena, pero los archivos de cabecera no son API. Hay campos privados allí. Si se añaden o eliminan ámbito privado se cambia la ejecución y no de la API.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top