Domanda

Molti linguaggi, come Java, C#, non separata dichiarazione da attuazione.C# è un concetto di classe parziale, ma l'attuazione della dichiarazione e ancora rimanere nello stesso file.

Perché non C++ sono lo stesso modello?È più pratico avere file di intestazione?

Mi riferisco alle attuali e future versioni di C++ standard.

È stato utile?

Soluzione

I routine capovolgere tra C # e C ++, e la mancanza di file header in C # è uno dei miei più grandi fastidi ricorrenti. Posso guardare un file di intestazione e imparare tutto quello che ho bisogno di sapere su una classe - di cosa si tratta funzioni membro sono chiamate, la loro sintassi chiamata, ecc. -, senza dover guadare attraverso le pagine del codice che implementa la classe

E sì, lo so sulle classi parziali e #regions, ma non è la stessa cosa. classi parziali effettivamente rendere il problema peggiore, perché una definizione di classe si sviluppa su più file. Per quanto riguarda #regions andare, non hanno mai sembrano essere ampliato nel modo che vorrei per quello che sto facendo in questo momento, quindi devo passare il tempo in espansione quei piccoli di più fino a ottenere la giusta visione.

Forse, se intellisense di Visual Studio ha funzionato meglio per C ++, non avrei un motivo valido per avere per fare riferimento a .h file così spesso, ma anche in VS2008, C ++ 'IntelliSense s non posso toccare C #' s

Altri suggerimenti

Compatibilità con il passato - file di intestazione non sono eliminate perché si spezzerebbe Compatibilità con il passato

.

I file header consentono per la compilazione indipendente. Non è necessario per accedere o anche avere i file di implementazione per compilare un file. Questo può rendere più agevole distribuito costruisce.

Questo permette anche di SDK da fare un po 'più facile. È possibile fornire solo le intestazioni e alcune librerie. Ci sono, naturalmente, modi per aggirare questo, che utilizzano altri linguaggi.

Bjarne Stroustrup ha definito un colpo di testa di un kludge.

Ma senza un formato binario standard che include i metadati necessari (come file di classe Java, .Net o file PE) non vedo alcun modo per implementare la funzionalità. Un ELF o a.out binario spogliato non ha gran parte delle informazioni si avrebbe bisogno di estrarre. E non credo che le informazioni sono sempre memorizzate in file di Windows XCOFF.

The Design e l'Evoluzione di C ++ , Stroustrup dà fuori un motivo in più ...

Lo stesso file di intestazione può avere due o più file di implementazione che possono essere contemporaneamente lavorato-upon da più di un programmatore, senza la necessità di un sistema di controllo del codice sorgente.

Questo potrebbe sembrare strano in questi giorni, ma credo che era un problema importante quando C ++ è stato inventato.

C è stato fatto per rendere la scrittura di un compilatore facilmente. Si fa un sacco di cose sulla base di quella linea di principio. Puntatori esistono solo per rendere la scrittura di un compilatore più facile, come do File di intestazione. Molte delle cose riportati al C ++ si basano sulla compatibilità con queste caratteristiche implementate per rendere più facile la scrittura del compilatore.

E 'una buona idea in realtà. Quando C è stato creato, C e Unix è gentile di una coppia. C porting di Unix, Unix corse C. In questo modo, C e Unix potrebbero diffondersi rapidamente da una piattaforma all'altra, mentre un sistema operativo basato sul montaggio doveva essere completamente ri-scritto per essere portati.

Il concetto di specificare un'interfaccia in un file e l'implementazione di un altro non è una cattiva idea a tutti, ma non è questo che i file di intestazione C sono. Essi sono semplicemente un modo per limitare il numero di passaggi un compilatore deve fare attraverso il vostro codice sorgente e consentire ad alcuni astrazione limitata del contratto tra i file in modo che possano comunicare.

Questi elementi, puntatori, i file di intestazione, ecc ... in realtà non offrono alcun vantaggio rispetto ad un altro sistema. Mettendo uno sforzo maggiore nel compilatore, è possibile compilare un oggetto di riferimento facilmente come un puntatore alla esattamente lo stesso codice oggetto. Questo è ciò che C ++ fa ora.

C è un grande, linguaggio semplice. Aveva un set di funzionalità molto limitata, e si potrebbe scrivere un compilatore senza molto sforzo. Il porting è generalmente banale! Io non sto cercando di dire che è un linguaggio scurrile o nulla, è solo che gli obiettivi primari del C quando è stato creato può lasciare residui nella lingua che sono più o meno inutile ora, ma stanno per essere tenuti in giro per la compatibilità.


Sembra che alcune persone non lo fanno davvero credono che C è stato scritto alla porta Unix, ecco: ( da )

  

La prima versione di UNIX è stato scritto   in linguaggio assembler, ma Thompson   intenzione era che sarebbe stato scritto   in un linguaggio di alto livello.

     

Thompson prima tentò nel 1971 di utilizzare   Fortran sul PDP-7, ma ha rinunciato   dopo il primo giorno. Poi ha scritto un   semplice linguaggio molto ha chiamato B,   che ha cominciato ad andare sul PDP-7. esso   hanno lavorato, ma ci sono stati problemi.   In primo luogo, perché l'implementazione era   interpretato, è stato sempre sarà   lento. In secondo luogo, le nozioni di base di B,   che si basava sulla parola orientata   BCPL, solo che non fosse giusto per un   Macchina byte orientato come il nuovo   PDP-11.

     

Ritchie utilizzato il PDP-11 per aggiungere i tipi   a B, che per un po 'è stato chiamato NB   per "Nuovo B", e poi ha iniziato a   scrivere un compilatore per esso. "In modo che il   prima fase di C è stato davvero questi due   fasi in rapida successione, da un lato,   alcuni cambiamenti linguistici da B, in realtà,   aggiungendo la struttura tipo senza troppo   molti cambiamenti nella sintassi; e facendo   il compilatore ", ha detto Ritchie.

     

"La seconda fase è stato più lento", ha detto   riscrivere UNIX in C. Thompson   iniziata nell'estate del 1972, ma aveva   due problemi: capire come far funzionare   la base co-routine, vale a dire, come   passare il controllo da un processo   un altro; e la difficoltà nell'ottenere   la struttura di dati corretta, poiché la   versione originale di C non ha avuto   strutture.

     

"La combinazione delle cose ha causato   Ken a rinunciare durante l'estate,"   Ritchie ha detto. "Nel corso dell'anno, ho aggiunto   strutture e probabilmente fatto la   codice compilatore un po 'meglio -   codice migliore - e così nel corso del prossimo   estate, che è stato quando abbiamo fatto la   concertato sforzo ed effettivamente fatto rifare   l'intero sistema operativo in C ".


Ecco un perfetto esempio di ciò che intendo. Dai commenti:

  

Puntatori esistere solo per rendere la scrittura di un compilatore più facile? No. I puntatori esistono perché sono il più semplice possibile l'astrazione sull'idea di riferimento indiretto. - Adam Rosenfield (un'ora fa)

Hai ragione. Al fine di attuare indirezione, puntatori sono il più semplice astrazione possibile l'attuazione. In nessun modo sono il più semplice possibile comprendere o utilizzare. Gli array sono molto più facili.

Il problema? Per implementare le matrici nel modo più efficiente come puntatori è necessario aggiungere o meno un mucchio di codice per il compilatore.

Non v'è alcuna ragione per cui non avrebbero potuto progettato C senza puntatori, ma con codice come questo:

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

ci vorrà un grande sforzo (da parte compilatori) per scomporre l'i esplicita + src e I + aggiunte dest e renderlo creare lo stesso codice che questo renderebbe:

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

Factoring che variabile "i" dopo il fatto è difficile. I nuovi compilatori possono farlo, ma allora non era possibile, e il sistema operativo in esecuzione su tale hardware scadente necessari piccole ottimizzazioni del genere.

Ora alcuni sistemi hanno bisogno di quel tipo di ottimizzazione (io lavoro su una delle piattaforme più lente intorno - Cavo set-top box, e la maggior parte della nostra roba è in Java) e nel raro caso in cui si potrebbe aver bisogno di esso, il nuovi compilatori C dovrebbero essere abbastanza intelligente per fare questo tipo di conversione da solo.

Se si desidera C ++ senza file di intestazione, allora ho buone notizie per voi.

E 'esiste già e si chiama D ( http://www.digitalmars.com/d/ index.html )

Tecnicamente D sembra essere molto più bello di C ++ ma non è abbastanza mainstream per l'uso in molte applicazioni in questo momento.

Uno degli obiettivi C ++ s 'è quello di essere un superset di C, ed è difficile per lui a farlo se non in grado di supportare file di intestazione. E, per estensione, se si desidera i file di intestazione accise si può anche prendere in considerazione l'escissione CPP (il pre-processore, non plus-plus) del tutto; sia in C # e Java non specificano macro pre-processori con i loro standard (ma va notato in alcuni casi essi possono essere e persino vengono utilizzati anche con queste lingue).

Come C ++ è stato progettato in questo momento, è necessario prototipi - proprio come in C - per verificare staticamente qualsiasi codice compilato che fa riferimento a funzioni esterne e classi. Senza file header, si dovrà digitare queste definizioni di classi e le dichiarazioni delle funzioni prima di utilizzarli. Per C ++ non utilizzare i file di intestazione, dovreste aggiungere una funzionalità nella lingua che avrebbe sostenuto qualcosa come parola chiave import di Java. Sarebbe un'aggiunta importante, e il cambiamento; per rispondere alla tua domanda di se sarebbe pratico: Io non la penso così - non a tutti

.

Molte persone sono a conoscenza di carenze delle file di intestazione e ci sono idee per introdurre più potente sistema di moduli in C ++. Si potrebbe voler dare un'occhiata a moduli in C ++ (Revision 5) da Daveed Vandevoorde.

Bene, C ++ per sé non dovrebbe eliminare i file di intestazione a causa di compatibilità all'indietro. Tuttavia, io credo che siano un'idea stupida in generale. Se si desidera distribuire un lib closed-source, queste informazioni possono essere estratte automaticamente. Se si vuole capire come utilizzare una classe w / o guardando l'attuazione, questo è ciò che i generatori di documentazione sono per, e fanno un diavolo di molto meglio di un lavoro.

C'è valore nel definire l'interfaccia di classe in un componente separato al file di implementazione.

Si può fare con le interfacce, ma se si va su questa strada, allora si sta implicitamente dicendo che le classi sono carenti in termini di separazione esecuzione dal contratto.

Modula 2 ha avuto l'idea giusta, moduli di definizione e moduli di implementazione. http://www.modula2.org/reference/modules.php

risposta

Java / C # s 'è un implicito implementazione dello stesso (anche se orientata agli oggetti.)

I file header sono un ripiego, perché i file di intestazione esprimono dettaglio di implementazione (come variabili private.)

Nel passare a Java e C #, trovo che se una lingua richiede il supporto IDE per lo sviluppo (in modo tale che le interfacce di classe pubblici sono navigabili nei browser di classe), allora questo è forse una dichiarazione che il codice non sta in piedi sulla sua propri meriti come particolarmente leggibile.

trovo il mix di interfacciamento con dettaglio di implementazione abbastanza orrendo.

Fondamentalmente, la mancanza di capacità di documentare la firma classe pubblica in modo sintetico file indipendente ben commentato dell'attuazione indica a me che la progettazione del linguaggio è stato scritto per comodità di autorialità, piuttosto comodità di manutenzione. Beh, io sto vagante su Java e C # ora.

Un vantaggio di questa separazione è che è facile da visualizzare solo l'interfaccia, senza da un editor avanzato .

Se si desidera che il motivo per cui questo non accadrà mai: si spezzerebbe praticamente tutto il software esistente C ++. Se si guarda ad alcune delle ++ C comitato documentazione di progetto, hanno esaminato varie alternative per vedere quanto il codice si spezzerebbe.

Sarebbe molto più facile cambiare l'istruzione switch in qualcosa a metà strada intelligente. Questo sarebbe solo rompere un po 'di codice. Non è ancora in corso per accadere.

A CURA per la nuova idea:

La differenza tra C ++ e Java, che rende i file necessari intestazione C ++ è che gli oggetti C ++ non sono necessariamente i puntatori. In Java, tutte le istanze di classe sono indicati con puntatore, anche se non sembra in questo modo. C ++ ha oggetti allocati sul mucchio e lo stack. Questo significa che C ++ ha bisogno di un modo di sapere quanto è grande un oggetto sarà, e dove i membri di dati sono in memoria.

Nessuna lingua esiste, senza file di intestazione. E 'un mito.

Guardate qualsiasi distribuzione libreria proprietaria per Java (non ho C # esperienza di cui parlare, ma mi aspetto che sia la stessa). Essi non vi danno il file sorgente completo; hanno appena ti danno un file con l'attuazione di ogni metodo oscurato ({} o {return null;} o simili) e tutto ciò che possono ottenere via con nascondersi nascosto. Non è possibile chiamare che tutt'altro che un colpo di testa.

Non v'è alcuna ragione tecnica, tuttavia, perché un compilatore C ++ C o potevano contare tutto in un file opportunamente contrassegnato come extern a meno che tale file sia compilato direttamente. Tuttavia, i costi per la compilazione sarebbe immenso perché né C né C ++ è veloce per analizzare, e questa è una considerazione molto importante. Qualsiasi metodo più complesso di intestazioni e fondendo fonte avrebbe incontrato rapidamente le questioni tecniche come la necessità per il compilatore di conoscere il layout di un oggetto.

I file header sono parte integrante del linguaggio. Senza file header, tutte le librerie statiche, librerie dinamiche, praticamente qualsiasi libreria di pre-compilato diventa inutile. File di intestazione anche rendere più facile per documentare tutto, e permettono di guardare oltre una libreria API / del file, senza andare oltre ogni singolo bit di codice.

Fanno anche più facile organizzare il vostro programma. Sì, bisogna essere costantemente il passaggio dalla sorgente alla intestazione, ma permettono anche di definire le API interne e private all'interno delle implementazioni. Ad esempio:

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() {

}

Se si #include <MySource.h>, quindi si ottiene my_library_entry_point.

Se si #include <MySource.c>, allora anche ottenere private_function_that_CANNOT_be_public.

Si vede come ciò possa essere una cosa molto brutta se si ha una funzione per ottenere un elenco di password, o una funzione che ha recepito l'algoritmo di cifratura, o una funzione che esporrebbe la struttura interna di un sistema operativo o una funzione che privilegi ha calpestato, ecc.

Oh sì!

Dopo la codifica in Java e C # è davvero fastidioso avere 2 file per ogni classe. Stavo pensando come posso unire senza rompere il codice esistente.

In realtà, è davvero facile. Basta mettere la definizione (implementazione) all'interno di una sezione #ifdef e aggiungere una definizione sulla riga di comando del compilatore per compilare il file. Questo è tutto.

Ecco un esempio:

/* 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

Nella riga di comando, compilare il file con

-D compiling_ClassA

Gli altri file che devono includere ClasseA può fare solo

#include "ClassA.cpp"

Naturalmente l'aggiunta della definizione sulla riga di comando può essere facilmente aggiunto con una macro di espansione (Visual Studio compilatore) o con un variabili automatiche (GNU make) e utilizzando la stessa nomenclatura per il nome definire.

Ancora non ho ben capito il senso di alcune dichiarazioni.Separazione di API e di attuazione, è una cosa molto buona, ma file di intestazione non sono API.Ci sono campi privati c'.Se si aggiunge o si rimuove privato campo di applicazione delle modifiche e non API.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top