Il semble que C ait ses propres quasi-objets, tels que des «structures», qui peuvent être considérés comme des objets (de la manière générale que nous pensons normalement).
Et aussi, les fichiers C eux-mêmes sont fondamentalement des "modules" séparés, non? Alors les modules ne sont-ils pas un peu comme des «objets» aussi? Je ne comprends pas pourquoi C, qui semble si semblable au C ++, est considéré comme un langage "procédural" de bas niveau où C ++ est un "orienté objet" de haut niveau.
* edit: (clarification) pourquoi et où, la ligne est-elle dessinée, qu'est-ce qu'un "objet" et ne l'est-il pas?
object-oriented
procedural
Templier noir
la source
la source
Réponses:
Ensemble, parcourons la page Wikipedia sur la programmation orientée objet et cochez les caractéristiques des structures de style C qui correspondent à ce que l'on considère traditionnellement comme étant du style orienté objet:
Les structures C sont-elles constituées de champs et de méthodes ainsi que de leurs interactions ? Non.
Est-ce que les structures C font l'une de ces choses en "première classe"? Non, le langage vous oppose à chaque étape.
Est-ce que les structures C font cela? Non.
Est-ce que les structures C font cela? Oui.
Non.
Une structure peut-elle envoyer et recevoir des messages? Peut-il traiter des données? Non.
Est-ce que cela se passe en C? Non.
Existe-t-il certaines de ces caractéristiques des structures C? Non.
Quelles caractéristiques des structures pensez-vous être "orientées objet"? Parce que je ne trouve personne d' autre que le fait que les structures définissent les types .
Maintenant, bien sûr, vous pouvez créer des structures avec des champs qui sont des pointeurs vers des fonctions. Vous pouvez faire en sorte que les structures aient des champs qui pointent vers des tableaux de pointeurs de fonction, correspondant aux tables de méthodes virtuelles. Etc. Vous pouvez bien sûr émuler C ++ en C, mais c’est une façon très peu idiomatique de programmer en C; vous feriez mieux d'utiliser simplement C ++.
Encore une fois, à quelles caractéristiques des modules pensez-vous qui les fait agir comme des objets? Les modules prennent-ils en charge l'abstraction, l'encapsulation, la messagerie, la modularité, le polymorphisme et l'héritage?
L'abstraction et l'encapsulation sont assez faibles. Évidemment les modules sont modulaires; c'est pourquoi ils s'appellent des modules. Messagerie? Ce n'est que dans le sens où un appel de méthode est un message et que les modules peuvent contenir des méthodes. Polymorphisme? Nan. Héritage? Nan. Les modules sont des candidats assez faibles pour les "objets".
la source
Le mot clé est "orienté", pas "objet". Même le code C ++ qui utilise des objets mais les utilise comme des structures n'est pas orienté objet .
C et C ++ peuvent faire de la programmation orientée objet (à l'exception de l'absence de contrôle d'accès en C), mais la syntaxe pour le faire en C est peu pratique (pour le moins qu'on puisse dire), tandis que la syntaxe en C ++ le rend très invitant. C est orienté vers la procédure, alors que C ++ est orienté vers les objets, malgré des capacités de base presque identiques à cet égard.
Le code qui utilise des objets pour implémenter des conceptions qui ne peuvent être créées qu'avec des objets (ce qui signifie généralement tirer parti du polymorphisme) est un code orienté objet. Le code qui utilise des objets ne représente guère plus que des poches de données, même en utilisant l'héritage dans un langage orienté objet, n'est en réalité qu'un code procédural plus compliqué qu'il ne le devrait. Le code en C qui utilise des pointeurs de fonction qui sont modifiés au moment de l’exécution avec des structures remplies de données est un peu en train de faire du polymorphisme, et pourrait être considéré comme étant "orienté objet", même dans un langage orienté procédure.
la source
Basé sur les directeurs de très haut niveau:
Un objet est une encapsulation de données et de comportements liés entre eux, de sorte qu'ils fonctionnent dans leur ensemble, pouvant être instanciés plusieurs fois et traités comme une boîte noire si vous connaissez l'interface externe.
Les structures contiennent des données mais pas de comportement et ne peuvent donc pas être considérées comme des objets.
Les modules contiennent à la fois le comportement et les données mais ne sont pas encapsulés de manière à ce qu'ils soient liés et ne puissent certainement pas être instanciés plusieurs fois.
Et c'est avant que vous abordiez l'héritage et le polymorphisme ...
la source
"structs" sont uniquement des données. Le test habituel rapide et erroné de l '"orientation d'objet" est le suivant: "Existe-t-il une structure permettant d'encapsuler le code et les données comme une seule unité?". C échoue, et est donc procédural. C ++ réussit ce test.
la source
this
pointeur explicite , mais dans ce cas, les données et les moyens de traitement des données seront encapsulés dans la structure.#include
d en elle, et rien moins éliminé par pas conditionnel inclus (#if
,#ifdef
, et analogues).Le C, tout comme le C ++, a la capacité de fournir l’ abstraction de données , qui est un des idiomes du paradigme de programmation orientée objet qui existait avant lui.
OOP en C ++ étend les moyens d'abstraction des données. Certains disent que c'est nocif , alors que d'autres le considèrent comme un bon outil lorsqu'il est utilisé correctement.
Cependant, vous trouverez de nombreux "hackers" de C qui prêchent que C est parfaitement capable d'abstraction et que les frais généraux créés par C ++ les empêchent seulement de résoudre le problème.
D'autres ont tendance à le considérer de manière plus équilibrée, acceptant à la fois les avantages et les inconvénients.
la source
Vous devez regarder de l'autre côté de la médaille: C ++.
En POO, nous pensons à un objet abstrait (et concevons le programme en conséquence), par exemple une voiture capable de s’arrêter, d’accélérer, de tourner à gauche ou à droite, etc. Une structure avec un ensemble de fonctions ne correspond tout simplement pas au concept.
Avec les "vrais" objets, nous devons par exemple masquer les membres, ou nous pouvons aussi avoir un héritage avec une relation "est une" et bien plus encore.
APRÈS AVOIR LU LES COMMENTAIRES CI-DESSOUS: Il est vrai que tout (ou presque) peut être fait avec C (c'est toujours vrai), mais à première vue, j'ai pensé que ce qui sépare c de c ++ est la façon dont vous pensez lors de la conception d'un programme.
La seule chose qui fait vraiment la différence est l'imposition de politiques par le compilateur . c'est-à-dire une fonction virtuelle pure, etc. mais cette réponse ne concernera que des problèmes techniques, mais je pense que la principale différence (comme mentionné) est la façon dont vous pensez en codant, car C ++ vous donne une meilleure syntaxe intégrée pour faire de telles choses, au lieu de faire de la POO un peu maladroit en C.
la source
Vous l'avez en quelque sorte dit vous-même. Bien que C ait des objets qui sont un peu comme des objets, ils ne sont toujours pas des objets et c’est pourquoi C n’est pas considéré comme un langage POO.
la source
Orienté objet fait référence à la fois à un motif architectural (ou même à un méta-motif) et aux langages dotés de fonctionnalités permettant de mettre en œuvre ou de rendre obligatoire l'utilisation de ce motif.
Vous pouvez implémenter un design "OO" (le bureau Gnome est peut-être le meilleur exemple de OO réalisé en C pur), j'ai même vu cela se réaliser avec COBOL!
Cependant, être capable de mettre en œuvre une conception OO ne rend pas le langage OO. Les puristes diraient que Java et C ++ ne sont pas vraiment des objets OO, car vous ne pouvez pas remplacer ou hériter des "types" de base tels que "int" et "char", et Java ne prend pas en charge l'héritage multiple. Mais comme ce sont les langages OO les plus utilisés et supportent la plupart des paradigmes, les programmeurs les plus "réels" qui sont payés pour produire du code fonctionnel les considèrent comme les langages OO.
C, d’autre part, ne supporte que les structures (comme le font COBOL, Pascal et des dizaines d’autres langages procéduraux), vous pouvez soutenir qu’il prend en charge l’héritage multiple en ce sens que vous pouvez utiliser n’importe quelle fonction sur n’importe quel élément de données, mais la plupart le considèrent comme un bogue. qu'une fonctionnalité.
la source
Regardons simplement la définition de OO:
C ne fournit aucune de ces trois. En particulier, il ne fournit pas la messagerie , qui est la plus importante.
la source
static
fonctions internal ( ) et des membres de données.Il existe un certain nombre d'ingrédients clés pour OO, mais les plus importants sont que la majorité du code ne sait pas ce qu'il y a à l'intérieur d'un objet (ils voient l'interface de surface, pas l'implémentation), que l'état d'un objet est une unité gérée. (c.-à-d. lorsque l'objet cesse d'être ainsi que son état), et lorsqu'un code appelle une opération sur un objet, il le fait sans savoir exactement ce que l'opération est ou implique (tout ce qu'il fait est de suivre un modèle pour “Message” sur le mur).
C fait très bien l’encapsulation; Un code qui ne voit pas la définition d'une structure ne peut pas (légitimement) jeter un coup d'œil à l'intérieur. Tout ce que vous avez à faire est de placer une définition comme celle-ci dans un fichier d’en-tête:
Bien sûr, il faudra une fonction qui construit
Foo
s (c’est-à-dire une usine) et qui devrait déléguer une partie du travail à l’objet alloué lui-même (c’est-à-dire, par le biais d’une méthode «constructeur»), ainsi qu’un chemin de disposer de l'objet à nouveau (en le laissant nettoyer via sa méthode "destructor") mais c'est des détails.L'envoi de méthode (c.-à-d. La messagerie) peut également s'effectuer par la convention selon laquelle le premier élément de la structure est en fait un pointeur sur une structure contenant des pointeurs de fonction et que chacun de ces pointeurs de fonction doit prendre un
Foo
premier argument. La répartition consiste alors à rechercher la fonction et à l'appeler avec le bon argument, ce qui n'est pas si difficile à faire avec une macro et un peu de ruse. (Cette table de fonctions constitue le cœur d'une classe dans un langage tel que C ++.)En outre, cela vous donne également une liaison tardive: tout ce que le code de répartition sait, c’est qu’il appelle un décalage particulier dans une table pointée par l’objet. Cela ne doit être défini que lors de l'affectation et de l'initialisation de l'objet. Il est possible d’utiliser des systèmes d’envoi encore plus complexes qui vous apportent plus de dynamisme d’exécution (à un coût élevé en termes de rapidité), mais ils sont au-dessus du mécanisme de base.
Pourtant, cela ne signifie pas que C est un langage OO. La clé est que C vous laisse faire tout le travail difficile d’écrire les conventions et le mécanisme d’envoi vous-même (ou d’utiliser une bibliothèque tierce). C'est beaucoup de travail. De plus, cela ne fournit pas de support syntaxique ou sémantique, donc implémenter un système de classes complet (avec des éléments comme l'héritage) serait inutilement douloureux; Si vous avez affaire à un problème complexe bien décrit par un modèle orienté objet, un langage orienté objet sera très utile pour la rédaction de la solution. La complexité supplémentaire peut être justifiée.
la source
Je pense que C est parfaitement correct et décent pour la mise en œuvre de concepts orientés objet, haussement d'épaules . La plupart des différences que je vois entre le sous-ensemble de dénominateurs communs de langages considérés comme orientés objet sont mineures et de nature syntaxique, de mon point de vue pragmatique.
Commençons par, disons, la dissimulation d'informations. En C, nous pouvons y parvenir simplement en cachant la définition d’une structure et en l’utilisant avec des pointeurs opaques. Que efficacement les modèles de la
public
contreprivate
distinction des champs de données que nous obtenons des classes. Et il est assez facile à faire et à peine anti-idiomatique, car la bibliothèque C standard repose énormément sur cela pour dissimuler des informations.Bien sûr, vous perdez la possibilité de contrôler facilement où la structure est allouée en mémoire en utilisant des types opaques, mais ce n'est qu'une différence notable entre, par exemple, C et C ++. Le C ++ est certainement un outil supérieur pour comparer sa capacité à programmer des concepts orientés objet sur C tout en maintenant le contrôle sur les dispositions de mémoire, mais cela ne signifie pas nécessairement que Java ou C # est supérieur à C à cet égard, car ces deux perdre complètement la capacité de contrôler où les objets sont alloués en mémoire.
Et nous devons utiliser une syntaxe similaire
fopen(file, ...); fclose(file);
à opposée àfile.open(...); file.close();
mais big whoop. Qui se soucie vraiment? Peut-être juste quelqu'un qui mise beaucoup sur l'auto-complétion dans son IDE. Je reconnais que cela peut être une fonctionnalité très utile d’un point de vue pratique, mais peut-être pas une qui nécessite une discussion sur le point de savoir si une langue est adaptée à la programmation orientée objet.Nous n'avons pas la capacité de mettre en œuvre efficacement les
protected
champs. Je vais totalement soumettre là. Mais je ne pense pas qu'il y ait de règle concrète qui dit: " Tous les langages OO devraient avoir une fonctionnalité permettant aux sous-classes d'accéder aux membres d'une classe de base auxquels les clients normaux ne devraient toujours pas accéder ." En outre, je vois rarement des cas d'utilisation pour des membres protégés qui ne craignent pas au moins de devenir un obstacle à la maintenance.Et bien sûr, nous devons "émuler" le polymorphisme OO avec des tables de pointeurs de fonction et des pointeurs vers ceux-ci pour un envoi dynamique avec un peu plus de passe-partout pour initialiser ces analogiques
vtables
etvptrs
, mais un peu de passe-passe ne m'a jamais causé beaucoup de chagrin.L'héritage est à peu près la même chose. Nous pouvons facilement modéliser cela par la composition et, dans les rouages internes des compilateurs, cela revient au même. Bien sûr, nous perdons la sécurité de type si nous voulons baisser le ton , et là, je dirais que si vous voulez être discret , il vous suffit de ne pas utiliser C pour cela, car ce que les gens font en C pour imiter le downcast peut être horrible d'un type sécurité, mais je préférerais que les gens ne soient pas abattus du tout. La sécurité de type est quelque chose que vous pouvez facilement commencer à manquer en C, car le compilateur offre une marge de manœuvre suffisante pour interpréter les choses sous forme de bits et d'octets, sacrifiant ainsi la possibilité de détecter les erreurs qui pourraient se produire au moment de la compilation, mais certains langages étaient considérés comme orientés objet. même pas statiquement tapé.
Donc, non, je pense que ça va. Bien sûr, je n’utiliserais pas C pour essayer de créer une base de code à grande échelle conforme aux principes de SOLID, mais cela n’est pas nécessairement dû à ses défauts dans le domaine orienté objet. Un grand nombre des fonctionnalités qui me manqueraient si j'essayais d'utiliser C à cette fin sont liées à des fonctionnalités de langage qui ne sont pas directement considérées comme une condition préalable à la POO, telles que la sécurité de type forte, les destructeurs qui sont automatiquement appelés lorsque des objets sortent de la portée, l'opérateur surcharge, modèles / génériques et traitement des exceptions. C'est quand je manque ces fonctionnalités auxiliaires que j'atteins pour C ++.
la source
foo_create
etfoo_destroy
etfoo_clone
, par exemplestruct Foo
un tel cas, tout ce dont nous avons besoin de conserver les invariants est de s’assurer que ses membres de données ne peuvent pas être consultés ni mutés par le monde extérieur, ce que donnent immédiatement les types opaques (déclarés mais non définis au monde extérieur). C'est sans doute une forme de dissimulation d'informations plus forte, comparable à celle d'unpimpl
C ++.Pas une mauvaise question.
Si vous appelez c un langage OO, vous devez également appeler à peu près tous les langages procéduraux OO. Cela rendrait donc le terme vide de sens. c n’a pas de support linguistique pour OO. Si a des structures, mais les structures
types
ne sont pas des classes.En fait, c n’a pas beaucoup de fonctionnalités comparées à la plupart des langues. Il est principalement utilisé pour sa rapidité, sa simplicité, sa popularité et son support, y compris des tonnes de bibliothèques.
la source