it-swarm.it

In che modo C differisce da C ++?

Molte persone hanno affermato che C++ è un linguaggio completamente diverso rispetto a C, ma Bjarne stesso ha affermato che C++ è un linguaggio che si estende da C, quindi è qui che ++ viene da. Quindi perché tutti continuano a dire che C e C++ sono lingue completamente diverse? In che modo C differisce da C++ oltre alle funzionalità estese in C++?

21
Joshua Partogi

Durante gli anni '80, quando lo sviluppo del C++ era appena agli inizi, il C++ era quasi un vero e proprio superset di C. Ecco come è iniziato tutto.
Tuttavia, nel tempo, sia il C che il C++ si sono evoluti e si sono differenziati l'uno dall'altro, anche se la compatibilità tra le lingue è sempre stata considerata importante.

Inoltre, le differenze tecniche tra C e C++ hanno reso gli idiomi tipici in quelle lingue e le cosiddette "buone pratiche" divergono ancora di più.

Questo è il fattore trainante dietro le persone che dicono cose come "non esiste un linguaggio come C/C++" o "C e C++ sono due lingue diverse". Sebbene sia possibile scrivere programmi accettabili sia per un compilatore C che per un C++, il codice è generalmente considerato né un esempio di buon codice C né un esempio di buon codice C++.

18

Lo stesso Stroustrup risponde che in le sue FAQ :

C++ è un discendente diretto di C che mantiene quasi tutta la C come sottoinsieme. C++ fornisce un controllo del tipo più forte di C e supporta direttamente una gamma più ampia di stili di programmazione rispetto a C. C++ è "una C migliore", nel senso che supporta gli stili di programmazione eseguiti usando C con un migliore controllo del tipo e un maggiore supporto notazionale (senza perdita di efficienza). Allo stesso modo, ANSI C è un C migliore di K&R C. Inoltre, C++ supporta l'astrazione dei dati, la programmazione orientata agli oggetti e la programmazione generica.

È il supporto per la programmazione orientata agli oggetti e la programmazione generica che rendono il C++ "completamente diverso" da C. È possibile è possibile scrivere quasi C puro e quindi compilarlo con un Compilatore C++ (purché tu ti occupi del controllo del tipo più rigoroso). Ma poi stai ancora scrivendo C - non stai scrivendo C++.

Se stai scrivendo C++, stai facendo uso delle sue funzionalità orientate agli oggetti e dei modelli e non è niente di simile a quello che vedresti in C.

20
Dean Harding

In parole povere, ciò che è considerato idiomatico in C non è assolutamente idiomatico in C++.

C e C++ sono in pratica linguaggi molto diversi, a causa del modo in cui le persone li usano. C punta al minimalismo, in cui C++ è un linguaggio molto complesso, con un lotto di funzionalità.

Ci sono anche alcune differenze pratiche: C può essere facilmente chiamato praticamente da qualsiasi linguaggio e spesso definisce l'ABI di una piattaforma, mentre C++ è piuttosto difficile da usare da altre librerie. La maggior parte delle lingue ha un FFI o un'interfaccia in C, anche le lingue implementate in C++ (Java, per esempio).

13
David Cournapeau

A parte l'ovvio fatto che C++ supporta la programmazione orientata agli oggetti, penso che tu abbia la tua risposta qui: http://en.wikipedia.org/wiki/Compatibility_of_C_and_C++

Quell'articolo contiene esempi di codice che mostrano cose che vanno bene in C ma non in C++. Per esempio:

int *j = malloc(sizeof(int) * 5); /* Implicit conversion from void* to int* */

Il porting di un programma C in C++ è spesso semplice e consiste principalmente nel correggere errori di compilazione (aggiunta di cast, nuove parole chiave ecc.).

4
Martin Wickman

C++ aggiunge non solo nuove funzionalità, ma nuovi concetti e nuovi modi di dire a C. Anche se C++ e C sono strettamente correlati, resta il fatto che per scrivere in modo efficace in una lingua, è necessario pensare nello stile di quella lingua. Anche il miglior codice C non può trarre vantaggio dai diversi punti di forza e idiomi del C++, quindi è più probabile che non piuttosto piuttosto cattivo codice C++.

2
Jon Purdy

Le "funzionalità estese", lo fai sembrare come in C++ hanno aggiunto come, macro variadiche o qualcosa del genere e basta. Le "funzionalità estese" in C++ sono un revisione completa del linguaggio e sostituiscono totalmente le migliori pratiche C poiché le nuove funzionalità C++ sono molto migliori delle funzioni C originali che le funzionalità C originali sono completamente e totalmente ridondante nella stragrande maggioranza dei casi. Suggerire che il C++ si estende semplicemente al C suggerisce che un moderno carro armato estende un coltellino per scopi di guerra.

2
DeadMG

La differenza è che in C pensi in modo procedurale e in C++ pensi in modo orientato agli oggetti. Le lingue sono abbastanza simili ma l'approccio è molto diverso.

1
Ant

Mentre C++ può essere un super insieme di C in termini sintattici, vale a dire qualsiasi costrutto del programma C può essere compilato dal compilatore C++.

Tuttavia, non scrivi quasi mai un programma C++ come faresti con il programma C. L'elenco può essere infinito o potrebbe essere qualcuno dovrebbe semplicemente fare ulteriori ricerche per metterlo come rapporti esaustivi. Tuttavia, sto mettendo alcuni suggerimenti che fanno le differenze chiave.

Il punto del post corrente è che C++ ha le seguenti caratteristiche che un buon programmatore C++ deve usare come buone pratiche di programmazione anche se è possibile compilare C equivalente.

Come dovrebbe essere fatto in C++ su C

  1. Classi ed ereditarietà. Queste sono le differenze più importanti che consentono l'orientamento sistematico degli oggetti che rende l'espressione della programmazione molto potente. Immagino che questo punto non abbia bisogno di spiegazioni migliori. Se sei in C++, quasi sempre, è meglio usare le classi.

  2. Privatizzazione: le classi e persino le strutture hanno membri privati. Ciò rende possibile l'incapsulamento di una classe. L'equivalente in C consiste nel digitare l'oggetto come void * nell'applicazione in modo che l'applicazione non abbia accesso alle variabili interne. Tuttavia, in C++ puoi avere elementi con classi sia pubbliche che private.

  3. Passa per riferimento. C++ consente la modifica in base al riferimento, per il quale è richiesto il passaggio di puntatori. Il pass-by-reference mantiene il codice molto pulito e molto più sicuro contro i rischi dei puntatori. Puoi anche passare il puntatore in stile C e funziona - ma se sei in C++ stai meglio finché

  4. nuovo ed elimina vs. malloc e gratuito. Le nuove istruzioni () e delete () non solo allocano e de-allocano la memoria, ma consentono anche l'esecuzione del codice come parte di destruct-er da chiamare in una catena. Se stai usando C++, in realtà è MALE usare malloc e free.

  5. Tipi di I/O e sovraccarico dell'operatore Il sovraccarico dell'operatore rende il codice leggibile o più intuitivo se eseguito correttamente. Lo stesso vale per gli operatori << e >> io. Il modo C per farlo sarebbe usare i puntatori a funzione - ma è disordinato e solo per i programmatori avanzati.

  6. Usando "stringa". Il carattere * di C funziona ovunque. Quindi C e C++ sono praticamente gli stessi. Tuttavia, se sei in C++, è sempre molto meglio (e più sicuro) usare le classi String che ti salvano dai pericoli delle matrici durante l'esecuzione che sono quasi tutte le cose.

Funzionalità di cui non sarei ancora fan in C++ 1. Modelli - Anche se non uso modelli pesanti in molti codici - può rivelarsi molto potente per le librerie. Non c'è quasi nessun equivalente in C. Ma in un giorno normale, specialmente se stai perdendo matematicamente.

  1. Puntatori intelligenti - Sì, sono molto intelligenti! E come la maggior parte delle cose intelligenti, iniziano bene e diventano più disordinati in seguito! Non mi piace usare

Cose che mi piacciono di C e che mancano in C++

  1. Algoritmi polimorfici usando i puntatori a funzione. In C, quando si eseguono algoritmi complessi, a volte è possibile utilizzare un set di puntatori a funzione. Questo rende vero il polimorfismo in modo potente. Quando sei in C++ puoi [~ # ~] puoi [~ # ~] usare i puntatori a funzione - ma non va bene. Dovresti usare solo metodi - altrimenti preparati a diventare disordinato. L'unica forma di polimorfismo nelle classi C++ è il sovraccarico di funzioni e operatori, ma è piuttosto limitante.

  2. Discussioni semplici Quando si creano thread sono stati pthread - è abbastanza semplice e gestibile. Diventa quando è necessario creare thread che dovrebbero essere "privati" per le classi (in modo che abbiano accesso ai membri privati). C'è boost tipo di framework - ma niente nel C++ di base.

Dipan.

0
Dipan Mehta

Alcune funzionalità linguistiche, anche se sono aggiunte, possono cambiare completamente il modo in cui la lingua deve essere praticamente utilizzata. Ad esempio, considera questo caso:

lock_mutex(&mutex);

// call some functions
...

unlock_mutex(&mutex);

Se quel codice sopra riguardava le funzioni di chiamata implementate in C++, potremmo trovarci in un mondo di problemi, dato che una qualsiasi di quelle chiamate di funzione potrebbe lanciare e non sbloccheremo mai il mutex in quei percorsi eccezionali.

I distruttori non sono più nel regno della convenienza per aiutare i programmatori a evitare di dimenticare di liberare/liberare risorse a quel punto. RAII diventa un requisito pratico perché non è umanamente possibile anticipare ogni singola riga di codice che può essere lanciata in esempi non banali (per non parlare del fatto che quelle linee potrebbero non essere lanciate ora ma potrebbero in seguito con modifiche). Prendi un altro esempio:

void f(const Foo* f1)
{
    Foo f2;
    memcpy(&f2, f1, sizeof f2);
    ...
}

Tale codice, sebbene generalmente innocuo in C, è come il caos infernale che regna in C++, perché il memcpy bulldoz su bit e byte di questi oggetti e aggira cose come i costruttori di copie. Funzioni come memset, realloc, memcpy, ecc., Mentre gli strumenti quotidiani tra gli sviluppatori C erano soliti guardare le cose in modo piuttosto omogeneo di bit e byte in memoria, sono non in armonia con il sistema di tipo più complesso e ricco di C++. Il C++ incoraggia una visione molto più astratta dei tipi definiti dall'utente.

Quindi questi tipi di cose non consentono più al C++, da parte di chiunque cerchi di usarlo correttamente, di vederlo come un semplice "superset" di C. Questi linguaggi richiedono una mentalità, una disciplina e un modo di pensare molto diversi per usare nel modo più efficace .

Non sono nel campo che vede C++ come decisamente migliore in ogni modo, e in realtà la maggior parte delle mie librerie di terze parti preferite sono librerie C per qualche motivo. Non so perché esattamente, ma le librerie C tendono ad essere di natura più minimalista (forse perché l'assenza di un sistema di tipo così ricco rende gli sviluppatori più concentrati nel fornire le funzionalità minime richieste senza costruire un insieme ampio e stratificato di astrazioni), anche se spesso finisco semplicemente per mettere i wrapper C++ attorno a loro per semplificare e personalizzare il loro utilizzo per i miei scopi, ma quella natura minimalista è preferibile per me anche quando lo faccio. Amo davvero il minimalismo come una caratteristica interessante di una biblioteca per coloro che si prendono il tempo extra per cercare tali qualità, e forse C tende a incoraggiarlo, se non altro in virtù del fatto che un codice così ampio, stratificato e astratto sarebbe un vera PITA da sviluppare in C.

Preferisco il C++ molto più spesso, ma in realtà mi viene richiesto di utilizzare le API C piuttosto spesso per la più ampia compatibilità binaria (e per le FFI), anche se spesso le implemento in C++ nonostante l'uso di C per le intestazioni. Ma a volte quando si passa a un livello molto basso, come il livello di un allocatore di memoria o una struttura di dati di livello molto basso (e sono sicuro che ci sono ulteriori esempi tra coloro che eseguono la programmazione integrata), a volte può essere utile essere in grado di presumere che i tipi e i dati con cui stai lavorando siano assenti alcune funzionalità come vtables, costruttori e distruttori, in modo che possiamo trattarli come bit e byte da mescolare, copiare, liberare, riallocare. Per problemi di livello molto particolarmente basso, a volte può essere utile lavorare con un sistema di tipo molto più semplice fornito da C, e ovviamente tende a costruire più velocemente e così via.

n chiarimento

Un commento interessante qui ho voluto rispondere un po 'più in profondità (trovo che i commenti qui siano così severi sul limite di caratteri):

memcpy(&f2, f1, sizeof f2); è anche "il caos infernale che regna" in C se Foo ha dei puntatori proprietari, o è anche peggio, poiché mancano anche gli strumenti per affrontarlo.

Questo è un punto giusto, ma tutto ciò su cui mi sto concentrando è principalmente focalizzato sul sistema di tipi di C++ e anche rispetto a RAII. Uno dei motivi per cui tali tipi di funzioni di copia dei byte di raggi x memcpy o qsort rappresentano un pericolo pratico in C è che la distruzione di f1 E f2 Sopra sono espliciti (se hanno persino bisogno di distruzioni non banali), mentre quando i distruttori entrano in scena, diventano impliciti e automatizzati (spesso con grande valore per gli sviluppatori). Questo non vuol dire nemmeno lo stato nascosto come vptrs e così via che tali funzioni dovrebbero abbattere subito. Se f1 Possiede i puntatori e f2 Li copia in modo superficiale in un contesto temporaneo, allora non ci sono problemi se non proviamo a liberare esplicitamente quei puntatori proprietari una seconda volta. Con C++ questo è qualcosa che il compilatore vorrà fare automaticamente.

E questo diventa più grande se in genere in C, " If Foo ha dei puntatori proprietari ", poiché l'esplicitazione richiesta con la gestione delle risorse renderà spesso qualcosa che in genere è più difficile da trascurare mentre in C++, possiamo rendere un UDT non più banalmente costruibile/distruttibile semplicemente facendolo immagazzinare qualsiasi variabile membro che non è ' t banalmente costruibile/distruttibile (in un modo che è generalmente molto utile, ancora una volta, ma non se siamo tentati di usare funzioni come memcpy o realloc).

Il mio punto principale non è quello di cercare di argomentare alcun beneficio di questa esplicitazione (direi che se ce ne sono, sono quasi sempre appesantiti dai contro della maggiore probabilità di errore umano che ne deriva), ma semplicemente per dire che funzioni come memcpy e memmove e qsort e memset e realloc e così via non hanno spazio in una lingua con UDT così ricchi di caratteristiche e capacità come C++. Sebbene esistano a prescindere, penso che non sarebbe troppo contestato affermare che la stragrande e vasta maggioranza degli sviluppatori C++ sarebbe saggia per evitare tali funzioni come la peste, mentre si tratta di funzioni molto quotidiane in C, e io ' d sostengono che pongono meno problemi in C per la semplice ragione che il suo sistema di tipi è molto più semplice e, forse, "più stupido". La radiografia dei tipi C e il loro trattamento come bit e byte è soggetto a errori. Farlo in C++ è senza dubbio del tutto errato perché tali funzioni stanno combattendo contro caratteristiche fondamentali del linguaggio e ciò che incoraggia il sistema dei tipi.

Questo è in realtà il più grande appello a me di C, tuttavia, in particolare per quanto riguarda l'interoperabilità linguistica. Sarebbe molto, molto più difficile far capire a qualcosa come FFI di C # il sistema di tipo completo e le caratteristiche del linguaggio di C++ fino a costruttori, distruttori, eccezioni, funzioni virtuali, sovraccarico di funzione/metodo, sovraccarico dell'operatore, tutti i vari tipi di eredità, ecc. Con C è un linguaggio relativamente più stupido che è diventato piuttosto standard per quanto riguarda le API in modi che molte lingue diverse possono importare direttamente tramite FFI, o indirettamente tramite alcune funzioni di esportazione dell'API C nella forma desiderata (es: Java Native Interface). Ed è qui che per la maggior parte non ho altra scelta che usare C, dal momento che l'interoperabilità del linguaggio è un requisito pratico nel nostro caso (anche se spesso sto solo scrivendo interfacce C con C++ implementazioni dietro di loro).

Ma sai, sono un pragmatico (o almeno mi sforzo di esserlo). Se C fosse il linguaggio più disgustoso e sgarbato, soggetto a errori, brutto che alcuni dei miei coetanei appassionati di C++ affermavano che fosse (e mi considererei un appassionato di C++ solo che in qualche modo non ha portato a un odio di C da parte mia ; al contrario, ha avuto l'effetto opposto su di me di farmi apprezzare meglio entrambe le lingue nei loro aspetti e differenze), quindi mi aspetto che si presenti nel mondo reale sotto forma di alcuni dei più attivi e leali e prodotti e librerie inaffidabili scritti in C. E non lo trovo. Mi piace Linux, mi piace Apache, Lua, zlib, trovo OpenGL tollerabile per la sua lunga eredità contro tali requisiti hardware mutevoli, Gimp, libpng, Il Cairo, ecc. Almeno qualunque ostacolo pone la lingua non sembra porre problemi quanto scrivere alcune biblioteche e prodotti interessanti in mani competenti, e questo è davvero tutto ciò che mi interessa. Quindi non sono mai stato il tipo così interessato alle guerre linguistiche più appassionate, se non per fare un appello pragmatico e dire: "Ehi, c'è roba fantastica là fuori! Impariamo come l'hanno fatta e forse ci sono lezioni interessanti, non così specifiche per la natura idiomatica della lingua, che possiamo riportare a qualsiasi lingua (e) che stiamo usando. " :-D

0
Dragon Energy