Pourquoi je ne peux pas hériter de int en C++?
J'aimerais être capable de faire cela:
class myInt : public int
{
};
Pourquoi ne puis-je pas?
Pourquoi voudrais-je? Plus de la frappe. Par exemple, j'ai pu définir deux classes intA
et intB
, qui m'a laissé faire intA + intA
ou intB + intB
, mais pas intA + intB
.
"Ints ne sont pas des classes." Et alors?
"Ints n'ont pas de données sur les membres." Oui, ils le font, ils ont 32 bits, ou quoi que ce soit.
"Ints n'ont pas de fonctions membres." Eh bien, ils ont tout un tas d'opérateurs comme +
et -
.
- Parce que la langue n'a pas été conçu de cette façon.
- Les langages tels que C# vous permettent d'ajouter des "méthodes d'extension" pour les classes (et à peu près tout, y compris ints, sont des classes), généralement utilisé pour le format en chaînes ou ce que vous avez. Bien sûr, ce n'est pas jive avec la presque-nu-métal C++ modèle.
- Je pense que Neil commentaire cloué vers le bas. C'était une décision de conception pour ne pas faire de types primitifs classes. Il y a de bonnes raisons de le faire et de bonnes raisons contre. Comme tout dans le C++, cela, aussi, est justifiée par l'objectif de quasi-optimale de la performance.
- Bien que j'ai apprécié de Neil réponse, il n'a probablement pas faire beaucoup pour éduquer OP. Rappelle moi (n'en déplaise) de l'ingénierie de manuels scolaires: si vous ne l'avez pas déjà comprendre le sujet, l'explication est inutile. Puis de nouveau, j'ai eu un bon rire...
- "Ints ne sont pas des classes" alors? l'Héritage, le polymorphisme et l'encapsulation sont les clés de voûte de la conception orientée objet. Aucune de ces choses s'appliquent à ordinale types. Vous ne pouvez pas hériter d'un int, parce que c'est juste un tas d'octets et n'a pas de code. Il n'a pas une méthode de la table, donc il n'y a aucun moyen d'ajouter des méthodes ou de les remplacer.
- Comme pour les "Pourquoi voudrais-je? Plus de la frappe. Par exemple, j'ai pu définir deux classes de l'intA et intB, qui permettez-moi de faire l'intA+intA ou intB+intB, mais pas l'intA+intB", c'est absurde. Vous pouvez mettre en œuvre ces types sans hériter de int. Il suffit de définir un nouveau type à partir de zéro, et de définir ses
operator+
. Je ne vois pas le problème - Si votre syntaxe est légal, alors
intA+intB
serait de compiler, ce qui était ce que l'on voulait éviter. - Downvoted parce que l'OP est belligérants. La question a été répondu de manière adéquate. @Neil réponse est le meilleur: la langue n'a tout simplement pas travailler de cette façon. L'OP doit le laisser aller.
- Que faire si vous voulez toutes les opérations entiers de soutien? Assurément, il n'est pas beaucoup de joie à les mettre en œuvre pour l'intA, puis la même chose pour intB, etc. etc.
- Mais UncleBens, il y a la faille. Si vous voulez de type sécurisé opérateurs qui ne fonctionnent pas sur tous les types int, mais seulement à certains, vous allez avoir à re-mettre en œuvre tous les opérateurs de toute façon. Vous n'avez pas sauver quoi que ce soit en descendant à partir de quelque chose qui a déjà les opérateurs. Et si vous ne voulez que les opérateurs de travailler sur tous les types int, alors vous devriez utiliser int.
- Il peut ne pas être beaucoup de joie, mais il est nécessaire, parce que l'ensemble de la prémisse de la question est de je ne veux pas de ce type de travail dans un contexte où
int
est prévu. Il ne peut pas réutiliser tout int opérateurs, car cela permettrait à la chose exacte que l'OP voulait éviter. - Cela ne signifie pas encore que l'on doit l'accepter, et ne pas se demander s'il pourrait y avoir différents, mais générique et réutilisable solutions.
- Ne pas hériter de int pour but de faire dégénérer les classes qui violent LSP? Quel est le problème avec la création d'une nouvelle classe avec ints et les opérateurs de membres?
- Accepter quoi? L'OP propose une fonctionnalité qui, même si elle était possible, ne permettrait pas de réaliser ce qu'il a réellement envie de faire. Avant que vous pouvez blâmer la langue pour ne pas l'appui de sa fonction, il est utile de considérer que le dispositif serait effectivement de résoudre son problème. Dans ce cas, il ne serait pas.
- Non, @David, il n'en a pas. Il lui a fallu un certain temps pour enfin comprendre à quelle question il vraiment envie de demander, mais dans son deuxième commentaire à votre réponse, enfin, il a précisé qu'il. (Je vois que beaucoup de choses en question "pourquoi", où une personne a de la difficulté à exprimer ce qu'il veut savoir la justification d'une décision de conception plutôt que le chapitre et le verset qui dit que quelque chose est ou n'est pas autorisée.) Je ne vois aucune preuve qu'il rejetait les réponses à ses qui n'est pas encore finalisé question juste pour embêter les gens.
- bon point bon point de vue.
- Vous devriez changer le titre de votre question ce que vous cherchez n'est pas hériter de type int, mais avoir un autre type.
- Je suis content que cette question a obtenu les gens à parler et beaucoup de réflexion à ce sujet. Je pense que c'est une de ces questions que beaucoup de gens pensent qu'ils connaissent la réponse, mais quand il s'agit de formuler cette réponse, le mieux qu'ils viennent avec est: "Juste parce que". I. E. "je ne sais pas".
- Pourquoi aurait-on à faire un tel héritage?
typedef int CostumerId;
typedef int ProductId;
Costumer getCostumer(CostumerId cid);
ProductId pid = 10;
Costumer c = getCostumer(pid); // mistake allowed!!
si c'étaitclass CostumerId: int {}; and class ProductId: int {};
il ne serait pas autorisé. Si je viens de composerCostumerId { int id; }
je vais avoir de la surcharge de tous les opérateurs pour obtenir la pleine fonctionnalité, comme(pid++ == ++pid || pid != pid--).
- nope,
class ProductId { ... int i; public: operator int() {return i;} ...};
va créer un nouveau, de différent objet temporaire. Vous ne pouvez toujours pas faireProductId pid; .... pid++;
-- vous avez encore besoin de surcharger l'opérateur++ pour compiler. S'il était possible d'hériter deint
, tous ceux de l'opérateur primordial serait donnée pour gratuit. - oups, vous avez raison, la suppression de mon commentaire précédent
Vous devez vous connecter pour publier un commentaire.
Neil commentaire est très précis. Bjarne mentionné en considérant et en rejetant cette possibilité1:
Autant que le commentaire de la performance justifie pas faire int une classe, c'est (au moins pour la plupart) faux. En Smalltalk, tous les types sont les classes-mais près de toutes les implémentations du langage Smalltalk ont optimisations de sorte que la mise en œuvre peut être essentiellement identique à la façon dont vous ferais un non-class type de travail. Par exemple, le smallInteger classe représente 15 bits entier, et le '+' message est codé en dur dans la machine virtuelle, de sorte que même si vous pouvez tirer de smallInteger, il donne toujours des performances similaires à un type (bien que Smalltalk est assez différent de C++ qui dirigez l'exécution des comparaisons sont difficiles et il est peu probable beaucoup de sens).
Le bit qui est "perdu" dans le langage Smalltalk mise en œuvre de smallInteger (la raison pour laquelle il ne représente que 15 bits au lieu de 16) ne serait probablement pas nécessaire en C ou C++. Smalltalk est un peu comme Java -- lorsque vous "définir un objet" vous êtes vraiment seulement la définition d'un pointeur vers un objet, et vous devez allouer dynamiquement un objet pour qu'il point. Ce que vous manipuler, transmettre à une fonction comme paramètre, etc., c'est toujours juste le pointeur, pas de l'objet lui-même.
C'est pas comment smallInteger est mis en œuvre -- il y a dans son cas, ils ont mis la valeur de l'entier directement dans ce qui serait normalement le pointeur. Pour faire la distinction entre un smallInteger et un pointeur, ils ont la force de tous les objets alloués à même les limites d'octets, de sorte que le LSB est toujours clair. Un smallInteger a toujours le LSB ensemble.
La plupart de ce qui est nécessaire, cependant, parce que Smalltalk est dynamiquement typé, il doit être en mesure de déduire le type en regardant la valeur elle-même, et smallInteger est essentiellement l'aide que LSB type de balise. Étant donné que C++ est statiquement typé, il n'y a pas besoin d'en déduire le type de la valeur, de sorte que vous ne serait probablement pas besoin de "déchets" qui bits sur un type de balise.
1. Dans La Conception et l'Évolution de C++, §15.11.3.
short
, et je doute qu'il peut être utilisé pour faire compact bitfields. Si le coût pour être en mesure de tirer à partir des matières premières les types d'entiers est un peu de surcharge par entier, il est beaucoup trop élevé pour un langage comme C++. C'est une approche valable dans la conception de langage en général, mais une langue qui ne qui ont des problèmes de compatibilité avec C.long long
.int
, mais il va toujours avoir des problèmes de compatibilité avec C.Int est un type ordinal, pas une classe. Pourquoi voudriez-vous?
Si vous avez besoin d'ajouter des fonctionnalités à "int", envisager la construction d'un agrégat de classe qui a un champ de type entier, et les méthodes qu'exposer ce que des fonctionnalités supplémentaires que vous avez besoin.
Mise à jour
@OP "Ints ne sont pas des classes" alors?
Héritage, le polymorphisme et l'encapsulation sont les clés de voûte de la conception orientée objet. Aucune de ces choses s'appliquent à ordinale types. Vous ne pouvez pas hériter d'un int, parce que c'est juste un tas d'octets et n'a pas de code.
Entiers, caractères, et d'autres ordinale types n'ont pas méthode des tables de, donc il n'y a aucun moyen d'ajouter des méthodes ou de les remplacer, ce qui est vraiment le cœur de l'héritage.
Qui n'a pas de sens. Vous pouvez faire tout cela sans hériter de quoi que ce soit. (Et, d'autre part, je ne vois pas comment vous pourriez peut-être obtenir l'aide de la succession.) Par exemple,
De remplir les blancs, et vous avez un type qui permet de résoudre votre problème. Vous pouvez faire
SpecialInt + SpecialInt
ouint + int
, maisSpecialInt + int
ne compile pas, exactement comme vous le vouliez.D'autre part, si l'on prétendait que l'héritage de int était légal, et notre
SpecialInt
dérivé deint
, puisSpecialInt + int
serait de la compilation. Héritant serait la cause du problème exact que vous voulez éviter. Pas hériter évite le problème facilement.Ceux qui ne sont pas des fonctions de membre du bien.
Si l'OP veut vraiment comprendre POURQUOI C++ est la façon dont il est, alors il devrait vous en procurer une copie de Stroustup du livre "La Conception et l'Évolution de C++". Il explique la raison pour cela et beaucoup d'autres décisions de conception dans les premiers jours de C++.
Parce que l'int est un type natif, et non pas une classe
Edit: déplacement de mes commentaires dans ma réponse.
Il vient de la C du patrimoine et ce qui, exactement, primitives représentent. Une primitive de c++ n'est qu'une collection d'octets qui ont peu de sens, sauf pour le compilateur. Une classe, d'autre part, a une table de fonction, et une fois que vous commencez à aller en bas de la succession et de l'héritage virtuel chemin, alors vous avez une vtable. Aucune de ce qui est présent dans un primitif, et en le faisant vous présenter: a) pause beaucoup de code c qui suppose un int est de 8 octets seulement, et b) de rendre les programmes prennent beaucoup plus de mémoire.
Penser d'une autre manière. int/float/char n'ont pas de membres de données ou de méthodes. Pensez à les primitives comme les quarks - ils sont les blocs de construction que vous ne pouvez pas subdiviser, vous les utiliser pour faire des choses plus importantes (toutes mes excuses si mon analogie est un peu hors, je ne connais pas assez la physique des particules)
int
n'est pas une classe; dans certaines languesint
est une classe.int
, pourquoi voudriez-vous ré-inventer int? :]class Int { public: int x; };
pour compiler vers le bas pour le même code queint
.typage fort d'entiers (et les flotteurs, etc) en c++
Scott Meyer (Effective c++ a une très efficace et puissant solution à votre problème de faire le typage fort de types de base en c++, et il fonctionne comme ceci:
Typage fort est un problème qui peut être traitée et évaluée au moment de la compilation, ce qui signifie que vous pouvez utiliser les ordinaux (typage faible) pour de multiples types au moment de l'exécution en déploiement d'applications, et de l'utilisation d'une compilation spéciale de la phase de fer inapproprié combinaisons de types au moment de la compilation.
Vous définissez ensuite votre
Time
,Mass
,Distance
être des classes à tous (et seulement) les opérateurs appropriés à surcharger les opérations appropriées. En pseudo-code:Une fois cela fait, votre compilateur va vous dire toutes les endroits que vous avez violé les règles codées dans les classes ci-dessus.
Je vous laisse trouver le reste des détails vous-même, ou d'acheter le livre.
Date
exemple?Ce que les autres ont dit, c'est vrai...
int
est une primitive en C++ (un peu comme en C#). Cependant, vous pouvez obtenir ce que tu voulais dire par la simple construction d'une classe autour deint
:Vous pouvez alors hériter de tout ce que vous jolly souhaitez.
explicit
pour empêcher la conversion automatique.int
type. Mais une fois que vous faites, vous pouvez alors faire un type de modèle qui prendmin
etmax
valeurs admissibles, et toutes les fonctions de membre peut faire le contrôle de la portée.int
est votre point de vue, n'oubliez pas: vous voulez plus de vérification de type. Permettant toutes les opérations tels que les entiers n'est le contraire.Personne n'a mentionné que le C++ a été conçu pour avoir (surtout) la rétro-compatibilité avec le C, afin de faciliter le chemin de mise à niveau pour les codeurs C donc
struct
défaut à tous les membres du public etc.Avoir
int
comme une classe de base que vous pourriez remplacer serait fondamentalement compliquer la règle pas de fin et de faire le compilateur de la mise en œuvre infernale qui, si vous souhaitez existant des codeurs et des éditeurs de compilateurs à l'appui de votre naissante de la langue n'était probablement pas la valeur de l'effort.int
? Je n'ai pas besoin de mon propre compilateur pour prouver que.Int
classe qui n'a pas la capacité d'avoir des fonctions virtuelles est très limité comme une classe de base, et donc sans doute pas la peine d'avoir. Du point de vue de la mise en œuvre, une classe de fonctions virtuelles besoin d'une vtable pointeur par exemple.En C++ les types intégrés ne sont pas des classes.
Comme les autres, je dis, ne peut pas être fait depuis int est un type primitif.
Je comprends la motivation, si, si c'est pour taper plus fort. Il a même été proposé pour C++0x qu'un type spécial de typedef devrait être suffisant pour que (mais cela a été rejeté?).
Peut-être quelque chose qui pourrait être atteint, si vous avez fourni la base wrapper vous-même. E. g quelque chose comme ce qui suit, qui nous l'espérons utilise curieusement récurrents des modèles d'une manière légale, et ne nécessite que la dérivation d'une classe et de fournir un constructeur approprié:
Mais si vous suivez les conseils que vous devriez juste de définir un nouveau type et de la surcharge des opérateurs, vous pouvez prendre un coup d'oeil à Coup de pouce.Les opérateurs
Bien, vous n'avez pas vraiment besoin d'hériter de quelque chose qui n'a pas obtenu un membre virtuel fonctions. Donc, même si
int
ont été une classe, il n'y aurait pas un plus sur la composition.Pour ainsi dire, l'héritage virtuel est la seule vraie raison pour laquelle vous pourriez avoir besoin de l'héritage de toute façon; tout le reste est juste vous sauver des masses de taper du temps. Et je ne pense pas qu'un
int
classe/type avec des membres virtuels serait la meilleure chose à imaginer dans le C++ monde. Au moins pas pour vous, tous les joursint
.Que signifie le fait d'hériter d'un int?
"int" n'a pas de fonctions de membre; il n'a pas de données sur les membres, c'est une 32 (ou 64 bits de la représentation en mémoire. Il n'est pas vtable. Tout ce qu'il "a" (il n'a pas vraiment le même propre) sont certains opérateurs comme +-/* qui sont vraiment global de plus de fonctions que les fonctions de membre.
int
est membre des données.malloc
n'est pas définie en terme demmap
. Vous ne pouvez pas écrire mutex en terme de std C++. Entiers pourrait faire partie de la std lib.Vous pouvez obtenir ce que vous voulez avec une forte typedefs. Voir BOOST_STRONG_TYPEDEF
Plus général que le fait que "int est primitif" est-ce:
int
est un scalaire type, tandis que les classes sont globale types. Un scalaire est une valeur atomique, tandis qu'un agrégat est quelque chose avec les membres. L'héritage (au moins tel qu'il existe en C++) n'a de sens que pour un type de regroupement, parce que vous ne pouvez pas ajouter des membres ou des méthodes pour les scalaires, par définition, ils n'ont pas membres.class
est la syntaxe pour exprimer un type et sous-classement moyen de restreindre le domaine. comme naturals sont un sous-type des entiers, qui sont un sous-type de reals, etc.int
est un scalaire, et le C++ notion de sous-typage n'est pas significatif pour les scalaires." Les entiers n'étaient pas arbitrairement exclus — il n'est pas possible d'appliquer le concept tel qu'il existe pour eux. C'est pourquoi.Cette réponse est une implémentation de UncleBens réponse
mis en Primitives.php
Exemple:
Primitive<T>
plutôt que le type dérivé.Donc, de nouveau, de ne pas être utiles à l'objet de fortes typeness. Essayez d'exécuter UncleBens fonction main() à l'aide de votre classe. Que devrait faire la lumière là où vous en avez besoin pour améliorer.Primitive<T,N>
du même numéro, sans le savoir il en existe déjà un. Vous pouvez fairetemplate<class T, class B> class Primitive : public B {...
et passe vide nommé structures pourB
S'il vous plaît, excusez-moi pour mon mauvais anglais.
Il existe une différence majeure entre le C++ correcte de la construction comme ceci:
et le projet d'extension
Et cette différence se trouve sur le mot-clé
this
comportement.this
est un pointeur et à l'aide d'un pointeur de laisser peu de chances pour utiliser les registres pour les calculs, parce que dans conventuelles processeurs registres n'ont pas d'adresse. Pire, à l'aide du pointeur de faire le compilateur suspectes sur le fait que les deux pointeurs peuvent désigner la même mémoire.Cela va mettre une charge extraordinaire pour le compilateur d'optimiser triviales de la fpo.
Un autre problème est le nombre de bugs: reproduire exactement tous les comportements des opérateurs est absolument enclins à faire des erreurs (par ex faire de constructeur explicite n'interdit pas toutes les implicites des cas). La probabilité d'une erreur lors de la construction d'un tel objet est assez élevé. Il n'est pas équivalente à la possibilité de faire quelque chose thru dur travail ou de l'avoir déjà fait.
Compilateur réalisateurs permettrait d'introduire le type de code de vérification (avec peut-être quelques erreurs, mais le compilateur précision est beaucoup mieux que le code du client, en raison d'un bogue dans le compilateur de générer d'innombrables erreurs des cas), mais l'essentiel du comportement de l'opération restera exactement le même, avec le moins d'erreurs que d'habitude.
La proposition de solution de rechange (à l'aide de structures pendant la phase de débogage et de vrais chars optimisé lorsque ceux) est intéressante, mais présente des inconvénients: c'est augmenter la probabilité d'avoir des bugs uniquement en version optimisée. Et le débogage d'applications optimales est beaucoup plus coûteux.
On peut mettre en place une bonne proposition pour @Rocketmagnet initiale de la demande pour les entiers les types d'aide :
Le bug niveau sera très élevé, comme en utilisant un seul membre de truc, mais le compilateur va traiter ces types exactement comme intégré dans les entiers (y compris le registre de la capacité & optimisation), merci pour inline.
Mais ce truc ne peut pas être utilisé (malheureusement) pour les nombres flottants, et les plus beaux besoin est évidemment réel évalué les dimensions de la vérification. On ne peut pas mélanger les pommes et les poires: ajouter de la longueur et de la région est une erreur commune.
Stroustrup' invocation par @Jerry n'est pas pertinent. La virtualité est utile principalement pour le patrimoine public, et la nécessité est ici vers le privé de l'héritage. Compte autour de "chaotiques" C des règles de conversion (C++14 d'entre eux, ce qui n'est pas chaotique?) de type de base ne sont pas également utiles : l'objectif est de n'avoir aucun défaut, des règles de conversion, de ne pas suivre les standards.
Si je me souviens, c'était le principal ou l'un des principaux motifs de C++ n'a pas été considéré comme un véritable langage orienté objet. Java les gens disaient: "En Java, TOUT est un objet" 😉
int
est un objet. Ce n'est pas unclass
. Et non pas toutes les classes ont des fonctions virtuelles, non pas toutes les classes sont conçus pour servir de classe de base.Ceci est lié à la façon dont les articles sont stockés dans la mémoire. Un int en C++ est un type intégral, comme mentionné ailleurs, et est à seulement 32 ou 64 bits (un mot) dans la mémoire. Un objet, cependant, est stockée différemment dans la mémoire. Il est généralement stocké sur le tas, et il dispose de fonctionnalités liées à la polymorphisme.
Je ne sais pas comment l'expliquer mieux. Comment voulez-vous hériter du numéro de 4?
int x; struct { int i; } y;
Erik, veuillez décrire commentx
ety
sont stockés différemment dans la mémoire.y
est une instance de la anonyme struct définis à droite. Si elle avait un nom (par exemple,Y
), vous pouvez également l'instancier comme ceci:Y* z = new Y;
Les variablesx
,y
, et maintenantz
, sont tous les objets. (Cochez la norme pour la définition de l'objet; si vous pensez que c'est une "instance de la classe", vous avez tort.) Vous peut stocker des objets sur le tas, mais en disant qu'ils sont généralement il y a une exagération. Ils sont souvent sur la pile, trop. Les types intégraux sont stockés de la même façon que les autres types.Pourquoi ne pouvez-vous pas hériter de int, même si vous pourriez vouloir?
Performance
Il n'y a pas fonctionnelle raison pourquoi vous ne devriez pas être en mesure (en un point arbitraire de la langue) hérite de l'ordinal de types tels que int ou char, ou char* etc. Certains langages comme Java et Objective-C en fait fournir classe/objet (en boîte) versions du type de base, afin de répondre à ce besoin (ainsi que pour faire face à certaines autres conséquences désagréables de ordinale types n'étant pas des objets):
Mais même Java et objective-c préserver leur ordinale types pour l'utilisation... pourquoi?
La simple raisons sont la performance et la consommation de mémoire. Un ordinal type peut être généralement être construits, exploités, et passé par valeur en seulement une ou deux instructions X86, et ne consomme que quelques octets au pire. Un cours en général, ne peut - il utilise souvent 2x ou plus comme beaucoup de mémoire, et la manipulation de sa valeur peut prendre plusieurs centaines de cycles.
Cela signifie que les programmeurs qui comprennent ce sera généralement d'utiliser l'ordinal types pour mettre en œuvre la performance ou l'utilisation de la mémoire sensible de code, et d'exiger que la langue les développeurs prennent en charge les types de base.
Il convient de noter qu'un certain nombre de langues n'ont pas de ordinale types, en particulier les langages dynamiques tels que
perl
, qui repose presque entièrement sur un variadic type, ce qui est tout autre chose, et partage une partie de la surcharge des classes.