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, d'où son origine ++
. 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 ++?
programming-languages
c++
c
Joshua Partogi
la source
la source
Réponses:
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 ++.
la source
void *
mais C ++ ne l'a jamais fait. (N'a pas downvote)Stroustrup lui-même répond à cela dans sa FAQ :
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.
la source
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 beaucoup de fonctionnalités.
Il existe également des 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).
la source
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:
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.).
la source
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 est donc plus probable qu'improbable en fait un code C ++ plutôt mauvais .
la source
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 car 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 redondantes 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.
la source
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.
la source
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 infinie 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
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.
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.
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
nouveau et supprimer vs malloc et gratuit. Les instructions new () et delete () non seulement allouent et désallouent de 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 ++ - il est en fait MAUVAIS d'utiliser malloc et gratuit.
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.
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 - spécialement si vous manquez mathématiquement.
Les choses que j'aime dans C et qui manquent en C ++
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.
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 existe un type de framework boost - mais rien en C ++ de base.
Dipan.
la source
Certaines fonctionnalités du langage, même s'il s'agit d'ajouts, peuvent changer la façon dont la langue doit être utilisée. À titre d'exemple, considérons ce cas:
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:
Un tel code, bien que généralement inoffensif en C, est comme un enfer qui fait des ravages en C ++, car les
memcpy
bulldozers sur les bits et octets de ces objets et contournent des choses comme les constructeurs de copie. De telles fonctions telles quememset
,realloc
,memcpy
, etc., tandis que les outils quotidiens entre les développeurs C utilisés pour regarder les choses d'une manière assez homogène de bits et d' octets dans la mémoire, ne 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 pourquoi exactement, 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 comme 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 a tendance à encourager cela,
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 costructors 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 très bas niveau, il peut parfois être utile de travailler avec un système de type beaucoup plus simple que C fournit,
Une clarification
Un commentaire intéressant ici, je voulais répondre un peu plus en profondeur (je trouve que les commentaires ici sont si stricts sur la limite de caractères):
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 la copie d'octets aux rayons X
memcpy
ou lesqsort
types de fonctions présentent moins de danger pratique en C est que la destruction def1
etf2
au-dessus est explicite (si elle a même besoin d'une destruction non triviale), alors 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, etc. Sif1
possède des pointeurs etf2
shallow les copie 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 gros si généralement en C, " Si Foo a des pointeurs propriétaires", car l'explicitation requise avec la gestion des ressources rendra souvent quelque chose de plus difficile à ignorer alors qu'en C ++, nous pouvons faire un UDT plus trivialement constructible / destructible en lui faisant simplement stocker toute variable membre qui n'est pas 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
ourealloc
).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
etmemmove
etqsort
etmemset
etrealloc
et ainsi de suite n'ont pas leur place dans un langage avec des UDT aussi riches en fonctionnalités et capacités que C ++. Bien qu'ils existent malgré tout, je pense qu'il ne serait pas trop contesté de dire que la grande, 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 pratiquement pas d'autre choix que d'utiliser C, car l'interopérabilité du langage est une exigence pratique dans notre cas (bien que souvent je ''
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, quels que soient les obstacles posés par la langue, cela ne semble pas constituer une impasse en ce qui concerne l'écriture de bibliothèques et de produits sympas entre des mains compétentes, et c'est vraiment tout ce qui m'intéresse. les guerres de langues, sauf pour lancer un appel pragmatique et dire: «Hé, il y a des trucs sympas là-bas! quelle que soit la ou les langues que nous utilisons. " :-RÉ
la source
memcpy(&f2, f1, sizeof f2);
est aussi « hellfire régnante des ravages » dans C siFoo
a des pointeurs propriétaires, ou est encore pire, comme vous aussi manque les outils nécessaires pour faire face à cela. Donc les gens qui écrivent C ne font pas autant de choses comme çaFoo
instances peuvent maintenant vouloir détruire le tableau dynamique, ou le vecteur, ou quelque chose à cet effet. Je trouve souvent pour certains cas particuliers qu'il est utile de pouvoir écrire certaines structures de données pour s'appuyer sur le fait que la destruction est explicite plutôt qu'implicite.Foo
il y a des pointeurs propriétaires, nous pourrions lui donner un bon copier / déplacer ctor, dtor, utiliser la sémantique des valeurs, etc., et avoir un code beaucoup plus riche et plus sûr. Mais parfois, je me retrouve à atteindre C dans les cas où je veux généraliser une structure de données ou un allocateur au niveau homogène de bits et d'octets, avec certaines hypothèses que je peux faire sur les types qui ont tendance, dans leurs cas d'utilisation étroits, à être simplifiés un peu par de telles hypothèses, je me sens un peu plus confiant à faire en C.API void filter_image(byte* pixels, int w, int h);
un exemple simple par opposition à likeAPI void filter_image(ImageInterface& img);
(ce qui couplerait notre code à une telle interface d'image, rétrécissement de son applicabilité). Dans de tels cas, je viens parfois d'implémenter de telles fonctions en C car il y a peu à gagner en C ++, et cela réduit la probabilité qu'un tel code ait besoin de modifications futures.