web-dev-qa-db-fra.com

En quoi le C est-il différent du C ++?

Beaucoup de gens ont dit que C++ est un langage complètement différent de C, mais Bjarne lui-même a dit que C++ est un langage qui est étendu à partir de C donc c'est là que le ++ vient de. Alors pourquoi tout le monde continue de dire que C et C++ sont des langages complètement différents? En quoi le C est-il différent du C++ à part les fonctionnalités étendues du C++?

21
Joshua Partogi

Pendant les années 80, alors que le développement de C++ commençait à peine, C++ était presque un surensemble approprié de C. C'est ainsi que tout a commencé.
Cependant, au fil du temps, le C et le C++ ont évolué et ont divergé l'un de l'autre, même si la compatibilité entre les langages a toujours été considérée comme importante.

De plus, les différences techniques entre C et C++ ont rendu les idiomes typiques de ces langages et ce qui est considéré comme une "bonne pratique" divergent encore plus.

C'est le facteur qui motive les gens à dire des choses comme "il n'y a pas de langage comme C/C++" ou "C et C++ sont deux langages différents". Bien qu'il soit possible d'écrire des programmes acceptables à la fois pour un compilateur C et C++, le code n'est généralement considéré ni comme un exemple de bon code C ni comme un exemple de bon code C++.

18

Stroustrup lui-même répond que dans sa FAQ :

C++ est un descendant direct de C qui conserve presque tout C comme sous-ensemble. C++ fournit une vérification de type plus forte que C et prend directement en charge une plus large gamme de styles de programmation que C. C++ est "un meilleur C" dans le sens où il prend en charge les styles de programmation effectués à l'aide de C avec une meilleure vérification de type et une prise en charge plus notationnelle (sans perte) d’efficacité). Dans le même sens, ANSI C est un meilleur C que K&R C. En outre, C++ prend en charge l'abstraction des données, la programmation orientée objet et la programmation générique.

Il prend en charge la programmation orientée objet et la programmation générique qui rendent le C++ "complètement différent" du C. Vous pouvez presque écrire du C pur puis le compiler avec un Compilateur C++ (tant que vous vous occupez de la vérification de type plus stricte). Mais alors vous écrivez toujours du C - vous n'écrivez pas du C++.

Si vous écrivez C++, vous utilisez ses fonctionnalités orientées objet et modèle et cela ne ressemble en rien à ce que vous verriez en C.

20
Dean Harding

En termes simples, ce qui est considéré comme idiomatique en C n'est certainement pas idiomatique en C++.

C et C++ sont des langages très différents dans la pratique, en raison de la façon dont les gens les utilisent. C vise le minimalisme, où C++ est un langage très complexe, avec un lot de fonctionnalités.

Il existe également quelques différences pratiques: le C peut être facilement appelé à partir de pratiquement n'importe quel langage et définit souvent l'ABI d'une plate-forme, tandis que le C++ est assez difficile à utiliser à partir d'autres bibliothèques. La plupart des langages ont un FFI ou une interface en C, même les langages implémentés en C++ (Java, par exemple).

13
David Cournapeau

Outre le fait évident que C++ prend en charge la programmation orientée objet, je pense que vous avez votre réponse ici: http://en.wikipedia.org/wiki/Compatibility_of_C_and_C++

Cet article contient des exemples de code montrant des choses qui sont correctes en C mais pas en C++. Par exemple:

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

Le portage d'un programme C vers C++ est souvent simple et consiste principalement à corriger les erreurs de compilation (ajout de cast, nouveaux mots-clés, etc.).

4
Martin Wickman

C++ ajoute non seulement de nouvelles fonctionnalités, mais de nouveaux concepts et de nouveaux idiomes à C.Même si C++ et C sont étroitement liés, le fait demeure que pour écrire efficacement dans un langage, vous devez penser dans le style de ce langage. Même le meilleur code C ne peut pas tirer parti des différentes forces et idiomes du C++, et il est donc plus probable qu'improbable plutôt mauvais code C++.

2
Jon Purdy

Les "fonctionnalités étendues", vous le faites sonner comme en C++, ils ont ajouté des macros variadiques ou quelque chose comme ça. Les "fonctionnalités étendues" en C++ sont une refonte complète du langage et remplacent totalement les meilleures pratiques C parce que les nouvelles fonctionnalités C++ sont tellement meilleures que les fonctionnalités C originales que les fonctionnalités C originales sont complètement et totalement redondant dans la grande majorité des cas. Suggérer que C++ étend simplement C signifie qu'un char de combat moderne étend un couteau à beurre aux fins de faire la guerre.

2
DeadMG

La différence est qu'en C vous pensez de manière procédurale et en C++ vous pensez d'une manière orientée objet. Les langues sont assez similaires mais l'approche est très différente.

1
Ant

Alors que C++ peut être un super ensemble de C en termes syntaxiques - c'est-à-dire que toute construction de programme C peut être compilée par le compilateur C++.

Cependant, vous n'écrivez presque jamais un programme C++ comme vous l'auriez fait avec un programme C. La liste peut être interminable ou peut-être que quelqu'un devrait simplement faire plus de recherches pour la mettre sous forme de rapports exhaustifs. Cependant, je mets quelques pointeurs qui font les principales différences.

Le point de l'article actuel est que C++ a les fonctionnalités suivantes qu'un bon programmeur C++ doit utiliser comme bonnes pratiques de programmation même s'il est possible de compiler l'équivalent C.

Comment cela devrait-il être fait en C++ sur C

  1. Classes et héritage. Ce sont les différences les plus importantes qui permettent une orientation d'objet systématique qui rend l'expression de programmation très puissante. Je suppose - ce point n'a pas besoin d'une meilleure explication. Si vous êtes en C++ - presque toujours, il vaut mieux utiliser des classes.

  2. Privatisation - Les classes et même les structures ont des membres privés. Cela rend possible l'encapsulation d'une classe. L'équivalent en C consiste à transtyper l'objet en tant que void * vers l'application afin que l'application n'ait pas accès aux variables internes. Cependant, en C++, vous pouvez avoir des éléments avec des classes publiques et privées.

  3. Passez par référence. C++ permet une modification basée sur la référence, pour laquelle le passage de pointeurs est requis. Le passage par référence maintient le code très propre et plus sûr contre les dangers du pointeur. Vous pouvez également passer un pointeur de style C et cela fonctionne - mais si vous êtes en C++, vous êtes mieux tant que

  4. nouveau et supprimer vs malloc et gratuit. Les instructions new () et delete () non seulement allouent et désallouent la mémoire, mais permettent également au code de s'exécuter dans le cadre du destructeur à appeler dans une chaîne. Si vous utilisez C++ - c'est en fait MAUVAIS d'utiliser malloc et gratuit.

  5. Types d'E/S et surcharge d'opérateur La surcharge d'opérateur rend le code lisible ou plus intuitif s'il est bien fait. Idem pour les opérateurs << et >> io. La façon C de le faire serait d'utiliser des pointeurs de fonction - mais c'est compliqué et uniquement pour les programmeurs avancés.

  6. Utilisation de "chaîne". Le caractère * de C fonctionne partout. Donc C et C++ sont à peu près les mêmes. Cependant, si vous êtes en C++ - il est toujours préférable (et plus sûr) d'utiliser des classes String qui vous évitent les dangers des tableaux sur l'exécution qui sont presque toutes choses.

Fonctionnalités dont je ne serais toujours pas fan en C++ 1. Modèles - Bien que je n'utilise pas de modèles lourds dans de nombreux codes - cela peut s'avérer très puissant pour les bibliothèques. Il n'y a presque pas d'équivalent en C. Mais un jour normal - surtout si vous manquez mathématiquement.

  1. Pointeurs intelligents - Oui, ils sont très intelligents! Et comme la plupart des choses intelligentes - elles commencent bien et deviennent désordonnées plus tard! Je n'aime pas trop utiliser

Les choses que j'aime à propos de C et qui manquent en C++

  1. Algorithmes polymorphes utilisant des pointeurs de fonction. En C, lorsque vous exécutez des algorithmes complexes - vous pouvez parfois utiliser un ensemble de pointeurs de fonction. Cela rend le vrai polymorphisme d'une manière puissante. Lorsque vous êtes en C++, vous [~ # ~] pouvez [~ # ~] utiliser des pointeurs de fonction - mais c'est mauvais. Vous ne devriez utiliser que des méthodes - sinon soyez prêt à vous salir. La seule forme de polymorphisme dans les classes C++ est la surcharge de fonctions et d'opérateurs mais c'est assez limitant.

  2. Fils simples. Lorsque vous créez des threads étaient des pthreads - c'est assez simple et gérable. Cela se produit lorsque vous devez créer des threads qui sont censés être "privés" pour les classes (afin qu'ils aient accès à des membres privés). Il y a boost type de frameworks - mais rien en C++ basique.

Dipan.

0
Dipan Mehta

Certaines fonctionnalités du langage, même si elles sont des ajouts, peuvent changer la façon dont la langue doit pratiquement être utilisée. À titre d'exemple, considérons ce cas:

lock_mutex(&mutex);

// call some functions
...

unlock_mutex(&mutex);

Si ce code ci-dessus impliquait d'appeler des fonctions implémentées en C++, nous pourrions être dans un monde de problèmes, car n'importe lequel de ces appels de fonction peut lancer et nous ne déverrouillerons jamais le mutex dans ces chemins exceptionnels.

Les destructeurs ne sont plus dans le domaine de la commodité pour aider les programmeurs à éviter d'oublier de libérer/libérer des ressources à ce stade. RAII devient une exigence pratique car il n'est pas humainement possible d'anticiper chaque ligne de code qui peut lancer des exemples non triviaux (sans mentionner que ces lignes peuvent ne pas lancer maintenant mais peuvent plus tard avec des modifications). Prenons un autre exemple:

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

Un tel code, bien que généralement inoffensif en C, est comme un enfer qui fait des ravages en C++, car le memcpy passe au bulldozer sur les bits et octets de ces objets et contourne des choses comme les constructeurs de copie. De telles fonctions comme memset, realloc, memcpy, etc., tandis que les outils quotidiens parmi les développeurs C habitués à regarder les choses d'une manière plutôt homogène de bits et d'octets en mémoire, sont pas en harmonie avec le système de type plus complexe et plus riche de C++. C++ encourage une vue beaucoup plus abstraite des types définis par l'utilisateur.

Donc, ces types de choses ne permettent plus au C++, par quiconque cherche à l'utiliser correctement, de le considérer comme un simple "sur-ensemble" de C. Ces langages nécessitent un état d'esprit, une discipline et une façon de penser très différents pour être utilisés le plus efficacement possible. .

Je ne suis pas dans le camp qui voit le C++ comme carrément meilleur à tous égards, et en fait la plupart de mes bibliothèques tierces préférées sont des bibliothèques C pour une raison quelconque. Je ne sais pas exactement pourquoi, mais les bibliothèques C ont tendance à être de nature plus minimaliste (peut-être parce que l'absence d'un système de type aussi riche rend les développeurs plus concentrés sur la fourniture des fonctionnalités minimales requises sans construire un ensemble d'abstractions volumineux et en couches), bien que je finisse souvent par mettre des wrappers C++ autour d'eux pour simplifier et adapter leur utilisation à mes besoins, mais cette nature minimaliste est préférable pour moi même lorsque je fais cela. J'aime vraiment le minimalisme en tant que caractéristique attrayante d'une bibliothèque pour ceux qui prennent le temps supplémentaire de rechercher de telles qualités, et peut-être que C tend à encourager cela, ne serait-ce qu'en vertu du fait qu'un code aussi volumineux et en couches et abstrait serait un véritable PITA à développer en C.

Je préfère C++ beaucoup plus souvent qu'autrement, mais je suis en fait obligé d'utiliser les API C assez souvent pour la compatibilité binaire la plus large (et pour les FFI), bien que je les implémente souvent en C++ malgré l'utilisation de C pour les en-têtes. Mais parfois, quand vous allez vraiment bas niveau, comme au niveau d'un allocateur de mémoire ou d'une structure de données très bas niveau (et je suis sûr qu'il y a d'autres exemples parmi ceux qui font de la programmation embarquée), il peut parfois être utile d'être capable de supposer que les types et les données avec lesquels vous travaillez sont absents de certaines fonctionnalités comme les vtables, les costructeurs et les destructeurs, afin que nous puissions les traiter comme des bits et des octets à mélanger, copier, libérer, réallouer. Pour des problèmes de niveau très particulièrement bas, il peut parfois être utile de travailler avec un système de type beaucoup plus simple que C fournit, et bien sûr, il a tendance à se construire plus rapidement et ainsi de suite.

ne clarification

Un commentaire intéressant ici auquel je voulais répondre un peu plus en profondeur (je trouve que les commentaires ici sont si stricts sur la limite de caractères):

memcpy(&f2, f1, sizeof f2); est aussi "un ravage infernal" en C si Foo a des pointeurs propriétaires, ou est encore pire, car vous n'avez pas non plus les outils pour y faire face.

C'est un bon point, mais tout ce sur quoi je me concentre est principalement axé sur le système de type C++ et également sur RAII. L'une des raisons pour lesquelles ces types de fonctions de copie d'octets par rayons X memcpy ou qsort posent moins de danger pratique en C est que la destruction de f1 Et f2 Ci-dessus sont explicites (s'ils ont même besoin d'une destruction non triviale), tandis que lorsque les destructeurs entrent dans l'image, ils deviennent implicites et automatisés (souvent avec une grande valeur pour les développeurs). Cela ne veut même pas mentionner l'état caché comme les vptrs et ainsi de suite sur lesquels de telles fonctions pourraient être rasées. Si f1 Possède des pointeurs et que f2 Les copie superficiellement dans un contexte temporaire, cela ne pose aucun problème si nous n'essayons pas de libérer explicitement ces pointeurs propriétaires une deuxième fois. Avec C++, c'est quelque chose que le compilateur voudra automatiquement faire.

Et cela devient plus grand si généralement en C, " If Foo possède des pointeurs ", car l'explicitation requise avec la gestion des ressources rendra souvent quelque chose de plus difficile à ignorer alors qu'en C++, nous pouvons faire en sorte qu'un UDT ne soit plus trivialement constructible/destructible en le faisant simplement stocker toute variable membre qui n'est pas ' t trivialement constructible/destructible (d'une manière qui est généralement très utile, encore une fois, mais pas si nous sommes tentés d'utiliser des fonctions comme memcpy ou realloc).

Mon point principal n'est pas d'essayer de faire valoir un quelconque avantage de cette explicitation (je dirais que s'il y en a, ils sont presque toujours alourdis par les inconvénients de la probabilité accrue d'erreur humaine qui l'accompagne), mais simplement de dire que des fonctions comme memcpy et memmove et qsort et memset et realloc et ainsi de suite n'ont pas leur place dans une langue avec des UDT aussi riches en fonctionnalités et capacités en C++. Bien qu'ils existent malgré tout, je pense qu'il ne serait pas trop contesté de dire que la vaste, grande majorité des développeurs C++ serait sage d'éviter de telles fonctions comme la peste, alors que ce sont des types très quotidiens de fonctions en C, et je '' d soutiennent qu'ils posent moins de problèmes en C pour la simple raison que son système de type est beaucoup plus basique et peut-être "plus bête". La radiographie des types C et leur traitement comme des bits et des octets sont sujets aux erreurs. Faire cela en C++ est sans doute tout simplement erroné car de telles fonctions se battent contre des caractéristiques très fondamentales du langage et ce qu'il encourage du système de type.

C'est en fait le plus grand attrait pour moi de C, cependant, en particulier avec sa relation avec l'interopérabilité linguistique. Il serait beaucoup, beaucoup plus difficile de faire comprendre à quelque chose comme le FFI de C # le système de type complet et les fonctionnalités du langage C++ jusqu'aux constructeurs, destructeurs, exceptions, fonctions virtuelles, surcharge de fonction/méthode, surcharge d'opérateur, tous les différents types de l'héritage, etc. Avec C, c'est un langage relativement plus bête qui est devenu plutôt standard en ce qui concerne les API de manières que de nombreux langages différents peuvent importer directement via les FFI, ou indirectement via certaines fonctions d'exportation d'API C sous la forme souhaitée (ex: Java Native Interface). Et c'est là que je n'ai généralement pas d'autre choix que d'utiliser C, car l'interopérabilité du langage est une exigence pratique dans notre cas (bien que souvent j'écris simplement des interfaces C avec C++ implémentations derrière eux).

Mais vous savez, je suis pragmatique (ou du moins je m'efforce de l'être). Si C était ce langage le plus grossier et le plus véreux, sujet aux erreurs et méchant, certains de mes pairs passionnés de C++ le prétendaient (et je me considérerais comme un passionné de C++, sauf que d'une manière ou d'une autre, cela n'a pas conduit à une haine de C de ma part ; au contraire, cela a eu l'effet inverse sur moi de me faire mieux apprécier les deux langues à leurs propres égards et différences), alors je m'attendrais à ce que cela apparaisse dans le monde réel sous la forme de certains des plus buggés et des plus fuyants et des produits et des bibliothèques peu fiables étant écrits en C. Et je ne trouve pas cela. J'aime Linux, j'aime Apache, Lua, zlib, je trouve OpenGL tolérable pour son long héritage contre de telles exigences matérielles changeantes, Gimp, libpng, Cairo, etc. Au moins les obstacles que pose le langage ne semblent pas poser d'impasses dans la mesure où écrire des bibliothèques et des produits sympas entre des mains compétentes, et c'est vraiment tout ce qui m'intéresse. Donc, je n'ai jamais été aussi intéressé par les guerres linguistiques les plus passionnées, sauf pour lancer un appel pragmatique et dire: "Hé, il y a des trucs sympas! Apprenons comment ils l'ont fait et peut-être qu'il y a des leçons sympas, pas si spécifiques à la nature idiomatique de la langue, que nous pouvons ramener à la ou aux langues que nous utilisons. " :-RÉ

0
Dragon Energy