Bases de l'entrée C++ (explication détaillée de 10 000 mots !!!)

avant-propos

  Le langage C est un langage structuré et modulaire, adapté à la gestion de programmes à plus petite échelle. Pour les problèmes complexes et les programmes à grande échelle qui nécessitent un degré élevé d'abstraction et de modélisation, le langage C n'est pas adapté. Afin de résoudre la crise du logiciel, dans les années 1980, l'industrie informatique a proposé l'idée de la POO (programmation orientée objet : orientée objet), et des langages de programmation supportant la programmation orientée objet ont émergé au fur et à mesure que l'époque l'exigeait.
  En 1982, le Dr Bjarne Stroustrup a introduit et élargi le concept d'orienté objet sur la base du langage C, et a inventé un nouveau langage de programmation. Afin d'exprimer la relation d'origine entre le langage et le langage C, il est nommé C++. Par conséquent : C++ est produit sur la base du langage C. Il peut non seulement effectuer la programmation procédurale du langage C, mais également effectuer une programmation basée sur des objets caractérisée par des types de données abstraits, et peut également effectuer une programmation orientée objet.

scène contenu
C avec cours Classes et classes dérivées, membres publics et privés, construction et destruction de classes, amis, fonctions en ligne, surcharge des opérateurs d'affectation, etc.
C++1.0 Ajoutez des concepts de fonctions virtuelles, des surcharges de fonctions et d'opérateurs, des références, des constantes, etc.
C++2.0 Prise en charge plus complète de l'orientation objet, des nouveaux membres de protection, de l'héritage multiple, de l'initialisation d'objet, des classes abstraites, des membres statiques et des fonctions membres const
C++3.0 Poursuite de l'amélioration, introduction de modèles, résolution du problème d'ambiguïté causé par l'héritage multiple et gestion de la construction et de la destruction correspondantes
C++98 La première version du standard C++, prise en charge par la plupart des compilateurs, a été reconnue par l'Organisation internationale de normalisation (ISO) et l'American Standards Association. Elle réécrit la bibliothèque standard C++ sous forme de modèle et introduit STL (Standard Template Library).
C++03 La deuxième version de la norme C++ n'a pas de changements majeurs dans les fonctionnalités du langage, principalement : révision des erreurs, réduction de l'hétérogénéité
C++05 Le comité des normes C++ a publié un rapport de comptage (rapport technique, TR1), officiellement renommé C++0x, c'est-à-dire qu'il est prévu de le publier au cours de la première décennie de ce siècle
C++11 De nombreuses fonctionnalités ont été ajoutées pour faire de C++ un nouveau langage, telles que : expressions régulières, boucles for basées sur des plages, mots-clés automatiques, nouveaux conteneurs, initialisation de liste, bibliothèques de threads standard, etc.
C++14 L'extension de C++11 est principalement destinée à corriger des bogues et des améliorations dans C++11, telles que : les expressions lambda génériques, la déduction automatique du type de valeur de retour, les constantes littérales binaires, etc.
C++17 Quelques petites améliorations apportées à C++11, en ajoutant 19 nouvelles fonctionnalités, telles que : les informations textuelles static_assert() sont facultatives, l'expression Fold est utilisée pour les modèles de variables, les initialiseurs dans les instructions if et switch, etc.
C++20 La plus grande version depuis C++11, introduisant de nombreuses nouvelles fonctionnalités, telles que : modules (Modules), coroutines (Coroutines), plages (Ranges), concepts (Constraints) et d'autres fonctionnalités majeures, ainsi que des fonctionnalités existantes. , Lambda prend en charge les modèles, la portée de l'initialisation prend en charge, etc.
C++23 formuler

1. Mots clés C++

  Ce sont tous les mots-clés de C++, chacun ayant une signification particulière. Ici, un par un est gênant et difficile à comprendre, je l'expliquerai donc en détail lorsque je le rencontrerai plus tard.
insérez la description de l'image ici

2. Espace de noms

  En C/C++, il existe un grand nombre de variables, de fonctions et de classes à apprendre ultérieurement. Les noms de ces variables, fonctions et classes existeront tous dans la portée globale, ce qui peut entraîner de nombreux conflits. Le but de l'utilisation de l'espace de noms est de localiser le nom de l'identifiant pour éviter les conflits de nommage ou la pollution des noms.L'apparition du mot-clé namespace vise ce genre de problème.
  Par exemple, il existe une fonction rand() dans <stdlib.h>, qui est une fonction utilisée pour générer des nombres aléatoires.
insérez la description de l'image ici
  À ce stade, nous pouvons voir qu'il peut fonctionner normalement sans le fichier d'en-tête <stdlib.h>, voyons donc ce qui se passe après l'inclusion du fichier d'en-tête.
insérez la description de l'image ici
  Nous avons constaté que la compilation a échoué. C'est parce que le contenu du fichier d'en-tête sera développé pendant la compilation, et la fonction rand() aura le même nom que la variable globale rand que nous avons définie, donc elle sera redéfinie, donc l'espace de noms est nommé Space est créé en conséquence, et sa fonction est d'empêcher que cela se produise.
  Un espace de noms consiste à utiliser le mot-clé namespace pour ajouter n'importe quel nom et accolades. Mais vous pouvez observer que j'ai écrit WY :: rand dans la ligne de sortie, ce qui signifie sortir le rand dans l'espace de noms WY au lieu d'utiliser le rand dans le fichier d'en-tête.
insérez la description de l'image ici
  Un espace de noms est comme un mur invisible qui sépare les variables portant le même nom dans différents espaces. Vous pouvez trouver des variables dans l'espace dont vous avez besoin. Mais qu'en est-il des variables portant le même nom dans un espace de noms ? Les créateurs de C++ ont déjà réfléchi à ce problème, c'est-à-dire que les espaces de noms peuvent également être ouverts dans des espaces de noms, communément appelés poupées gigognes.
insérez la description de l'image ici
  Les espaces de noms peuvent définir des variables, des fonctions et des types. Cependant, il est à noter que lors de la définition d'un type de structure, il doit être accessible lors de l'accès àderrière la structureécrit. en même tempsLes espaces de noms portant le même nom sont autorisés dans le même projet, et le compilateur les fusionnera automatiquement lors de la compilation

int rand = 0;//全局变量
namespace WY
{
    
    
	int rand = 1;

	int Add(int a, int b)
	{
    
    
		return a + b;
	}

	struct Node
	{
    
    
		int data;
		int* next;
	};
}
int main()
{
    
    
  //域作用限定符
	printf("%d", rand);
	printf("%d", WY::rand);
	printf("%d", WY::Add(1,2));
	struct WY::Node node;

	return 0;
}

  Dans le passé, la voix C était encore utilisée pour simuler certains environnements, alors à quoi ressemble le C++ lui-même ? C++ possède son propre espace de noms et ses propres fichiers d'en-tête.

//C++标准库的命名空间,将标准库的定义与实现都放入了这个命名空间中
#include<iostream>
using namespace std;
int main()
{
    
    
	cout << "Wang You" << endl;
}

  Mais cette façon d'écrire développe tout le contenu de l'espace de noms, ce qui est très facile à causer des problèmes de redéfinition. Par exemple, lorsque vous écrivez un projet avec d'autres, vous utilisez le même nom de variable, et le résultat est lorsque vous l'exécutez ensemble à la fin Ils étendent tous leurs propres espaces de noms, donc n'y aurait-il pas de redéfinition ? Donc cette façon d'écrireDéconseillé lorsque vous travaillez avec d'autres, mais acceptable dans votre propre pratique quotidienne, Après tout, les noms de variables sont contrôlés par eux-mêmes, ce qui peut éviter cette situation.
  Dans le même temps, l'expansion peut également être entièrement ou partiellement développée. Par exemple, si la fonction Ajouter doit être utilisée fréquemment, elle peut être partiellement développée, de sorte qu'il n'est pas nécessaire d'ajouter un qualificatif de portée ( : : ) avant chaque utilisation.

//全部展开
using namespace WY;

//部分展开
using WY::Add;

3. Entrée et sortie C++

  En fait, il a été écrit une fois ci-dessus, s'il vous plaît voir:

#include<iostream>
using namespace std;
int main()
{
    
    
	int a;
	cin >> a;
	cout << "Wang You" << endl;
	return 0;
}

cout est utilisé pour la sortie, qui a la même fonction que printf en langage C, et l'autre est cin, qui a la même fonction que scanf.

Par rapport au langage C, il convient de noter que

  1. Lorsque vous utilisez l'objet de sortie standard cout (console) et l'objet d'entrée standard cin (clavier), vous devez inclure le fichier d'en-tête <iostream> et utiliser std par l'utilisation de l'espace de noms.
  2. cout et cin sont des objets de flux globaux et endl est un symbole C++ spécial qui représente la sortie de nouvelle ligne. Ils sont tous inclus dans le fichier d'en-tête <iostream>.
  3. <<est l'opérateur d'insertion de flux,>>est l'opérateur d'extraction de flux.
  4. Il est plus pratique d'utiliser l'entrée et la sortie C++ et n'a pas besoin de contrôler manuellement le format comme l'entrée et la sortie printf/scanf. L'entrée et la sortie de C++ peuvent identifier automatiquement le type de variable.
  5. En fait, cout et cin sont respectivement des objets de type ostream et istream. >> et << impliquent également une surcharge d'opérateurs et d'autres connaissances, qui seront expliquées plus tard, voici donc une simple étude de leur utilisation.

Lorsque l'espace de noms std est développé, la bibliothèque standard est entièrement exposée. Si nous définissons un type/objet/fonction avec le même nom que la bibliothèque, il y aura des conflits. Ce problème se produit rarement dans la pratique quotidienne, mais il est facile de se produire lorsqu'il existe de nombreux codes et à grande échelle dans le développement de projets. Par conséquent, il est recommandé de l'utiliser dans le développement de projets, en spécifiant l'espace de noms + en utilisant std :: cout pour développer les objets/types de bibliothèque communs lors de son utilisation comme std :: cout.

4. Paramètres par défaut

  Le paramètre par défaut consiste à spécifier une valeur par défaut pour le paramètre de la fonction lors de la déclaration ou de la définition de la fonction. Lors de l'appel de cette fonction, si aucun paramètre réel n'est spécifié, la valeur par défaut du paramètre formel est adoptée, sinon le paramètre réel spécifié est utilisé.
insérez la description de l'image ici
  Généralement, lors de l'appel d'une fonction, nous lui transmettrons des paramètres. La signification des paramètres par défaut est que lorsque vous ne transmettez pas de paramètres à la fonction, elle transmettra automatiquement les paramètres par défaut que vous avez définis par défaut (int a = 0).

4.1 Ministère global

void fun(int a = 10, int b = 20, int c = 30)
{
    
    
	cout << a << " ";
	cout << b << " ";
	cout << c << " ";
	cout << endl;
}

insérez la description de l'image ici
  De cela, nous pouvons également voirLes paramètres par défaut doivent être donnés de droite à gauche, donc les paramètres que nous donnons sont de gauche à droite, les données de gauche peuvent être affichées et transmises par nous, et les données de droite peuvent utiliser les paramètres par défaut.

4.2 Semi-défaut

  Examinons à nouveau les semi-défauts Comme leur nom l'indique, seuls certains d'entre eux ont des valeurs par défaut.

void fun(int a,int b,int c = 30)
{
    
    
	cout << a << endl;
	cout << b << endl;
	cout << c << endl;
}

insérez la description de l'image ici

Avis:

  1. Les paramètres semi-par défaut doivent être donnés séquentiellement de droite à gauche et ne peuvent pas être donnés alternativement.
  2. Les paramètres par défaut ne peuvent pas apparaître à la fois dans la déclaration et la définition de la fonction
  3. La valeur par défaut doit être une constante ou une variable globale
  4. Le langage C ne prend pas en charge (le compilateur ne prend pas en charge)

  Différentes déclarations et définitions apparaissent en même temps car si les paramètres par défaut donnés dans la définition sont différents des paramètres par défaut donnés dans la déclaration, le compilateur ne peut pas les distinguer, donc les paramètres par défaut (paramètres par défaut) sont tous donnés dans la définition.

5. Surcharge de fonctions

  La surcharge de fonctions est un cas particulier de fonctions. C++ permet à plusieurs fonctions du même nom avec des fonctions similaires d'être déclarées dans la même portée. Le paramètre formel répertorie ces fonctions avec le même nom (Nombre de paramètresoutaperoutype de commande) sont différents et sont souvent utilisés pour résoudre le problème de l'implémentation de fonctions similaires avec différents types de données.
insérez la description de l'image ici
  Le système correspondra automatiquement et appellera la fonction la plus correspondante en fonction de leurs types de paramètres, même si les noms de fonction sont les mêmes.

Mais il doit satisfaire la liste de paramètres formels (Nombre de paramètresoutaperoutype de commande) est différente, une seule de ces trois conditions est acceptable.

Alors, comment le compilateur fait-il la différence ?

  En fait, lorsque cette fonction est appelée à l'intérieur de l'éditeur, elle est trouvée en ajoutant son nom de fonction et son adresse. Le nom de fonction interne de chaque fonction lors de la liaison, le compilateur se basera sur le nom de fonction (fun) que vous avez écrit Ajoutez ensuite quelques symboles de le modifier en fonction de ses paramètres. Par exemple, dans VS2019, les noms de fonction des deux fonctions pendant le processus de liaison sont comme indiqué sur la figure, l'un est HN et l'autre est NH. Ainsi, le compilateur les distinguera avec précision.
insérez la description de l'image ici
  Dans le langage C, la modification du nom de la fonction interne est la même, donc le compilateur ne peut pas faire la distinction. Grâce à cela, je peux comprendre pourquoi le langage C ne peut pas supporter la surcharge, car il n'y a aucun moyen de distinguer les fonctions portant le même nom. C++ se distingue par des règles de modification de fonction. Tant que les paramètres sont différents, les noms modifiés sont différents et la surcharge est prise en charge.

Si les noms de fonction et les paramètres de deux fonctions sont identiques, mais que les valeurs de retour sont différentes, cela ne constitue pas une surcharge, car le compilateur n'a aucun moyen de faire la distinction lors de l'appel.

6. Citation

  Une référence n'est pas une nouvelle définition d'une variable, mais un alias (c'est-à-dire un surnom) pour une variable existante. Le compilateur n'ouvrira pas d'espace mémoire pour la variable de référence, et il partage le même espace mémoire avec la variable qu'il fait référence à.
insérez la description de l'image ici
  Par exemple, le nom d'un morceau d'espace est a, et vous lui donnez un surnom appelé b. Bien que le nom soit différent, c'est le même espace.
insérez la description de l'image ici
  Cela ressemble à deux noms, mais ils sont en fait le même espace, l'un est prospère et l'autre est endommagé. Tu es moi, et je suis ta relation. il faut être conscientLe type de référence doit être du même type que l'entité référencée

6.1 Caractéristiques des références

  1. Les références doivent être initialisées lorsqu'elles sont définies
  2. Une variable peut avoir plusieurs références
  3. Une fois qu'une référence fait référence à une entité, elle ne peut pas faire référence à une autre entité
int main()
{
    
    
	int a = 10;
	int& b;
	//正确写法:int& b = a;
	return 0;
}

  Il n'est pas acceptable d'écrire de cette façon, car vous aliasez une variable existante et elle ne peut pas exister en tant que surnom de quelqu'un d'autre sans initialisation.

int main()
{
    
    
	int a = 10;
	int& ra = a;
	int& raa = a;
	return 0;
}

  Il est possible d'écrire de cette façon, une variable peut avoir plusieurs surnoms. Mais un surnom ne peut être utilisé que par une seule personne, ne serait-ce pas gâché si n'importe qui pouvait l'utiliser, alorsUne fois qu'une référence fait référence à une entité, elle ne peut pas faire référence à une autre entité.
  Pour les variables modifiées par const, cela signifie qu'elles peuvent uniquement être lues mais pas écrites. Par conséquent, const doit également être ajouté lors de l'aliasing des variables const, afin qu'il ne puisse pas être modifié en ajoutant un surnom.

void test()
{
    
    
    const int a = 10;
    int& ra = a;   // 该语句编译时会出错,a为常量
    //正确写法:const int& ra = a;
    
    const int& ra = a;
    int& b = 10; // 该语句编译时会出错,b为常量
    //正确写法:const int& b = 10;
    
    const int& b = 10;
    double d = 12.34;
    int& rd = d; // 该语句编译时会出错,类型不同
    //正确写法:const int& rd = d;
}

  Et pour le dernier type qui est différent, pourquoi ajouter const ? En effet, un int temporaire sera généré en premier lors de l'exécution de la conversion de type impliciteconstante, convertissez d'abord la valeur de d du type double au type int et affectez-la à une variable temporaire, puis attribuez un alias à la variable temporaire. Comme il s'agit d'une constante et qu'elle ne peut pas être modifiée, il est également nécessaire d'ajouter const lors de la prise d'un alias.

6.2 Scénarios d'utilisation référencés

  En tant qu'argument d'une fonction afin que les valeurs de deux variables puissent être échangées sans avoir besoin de pointeurs.

void Swap(int& left, int& right)
{
    
    
   int temp = left;
   left = right;
   right = temp;
}

  comme valeur de retour. Le retour par référence sera plus rapide, car l'alias de la variable est retourné directement. Dans une fonction normale, la fonction est détruite après avoir été appelée, donc elle donne d'abord la valeur de retour à une variable temporaire, et la variable temporaire est renvoyée à la fonction principale. Il convient donc de noter que,Lorsqu'une référence est retournée, elle doit retourner une variable statique ou une variable sur le tas

int& Count()
{
    
    
   static int n = 0;
   n++;
   // ...
   return n;
}

Les valeurs sont utilisées comme paramètres ou types de valeur de retour. Lors du passage et du retour des paramètres, la fonction ne passe pas directement les paramètres réels ou ne renvoie pas directement la variable elle-même, mais passe les paramètres réels ou renvoie une copie temporaire de la variable, donc les valeurs sont utilisés comme paramètres Ou le type de valeur de retour est très inefficace, surtout lorsque le paramètre ou le type de valeur de retour est très grand, l'efficacité est encore plus faible.

6.3 Références et pointeurs

  Les pointeurs et les références sont utilisés différemment, mais l'implémentation sous-jacente est en fait la même. Examinons un tel morceau de code.

#include<iostream>
using namespace std;
int main()
{
    
    
	int a = 10;
	int* pa = &a;
	int& ra = a;

	++(*pa);
	++ra;
	return 0;
}

  Bien que je ne comprenne pas très bien l'assemblage, cela ne nous empêche pas de voir que pour l'arithmétique des pointeurs et l'arithmétique des références, le compilateur implémente le même assemblage à la couche inférieure, nous pouvons donc savoir que la référence est réellement implémentée via des pointeurs.
insérez la description de l'image ici
insérez la description de l'image ici

  1. Une référence définit conceptuellement un alias pour une variable, et un pointeur stocke l'adresse d'une variable.
  2. Les références doivent être initialisées lorsqu'elles sont définies, les pointeurs ne sont pas nécessaires

  3. Une fois que la référence fait référence à une entité lors de l'initialisation, elle ne peut pas faire référence à d'autres entités et le pointeur peut pointer vers n'importe quelle entité du même type à tout moment.
  4. Il n'y a pas de références NULL, mais il y a des pointeurs NULL
  5. La signification est différente dans sizeof : le résultat de référence est la taille du type de référence, mais le pointeur est toujours le nombre d'octets occupés par l'espace d'adressage (
    4 octets sous la plate-forme 32 bits)
  6. L'auto-incrémentation de la référence signifie que l'entité référencée augmente de 1, et l'auto-incrémentation du pointeur signifie que le pointeur décale la taille d'un type vers l'arrière
  7. Pointeurs multiniveaux, mais pas de références multiniveaux
  8. Il existe différentes façons d'accéder aux entités, le pointeur doit être explicitement déréférencé et le compilateur de référence le gère lui-même
  9. Les références sont relativement plus sûres à utiliser que les pointeurs

7. Fonctions en ligne

  Une fonction modifiée avec inline est appelée une fonction inline. Lors de la compilation, le compilateur C++ la développera à l'endroit où la fonction inline est appelée. Il n'y a pas de surcharge pour l'appel de fonction pour construire un cadre de pile. Les fonctions inline améliorent l'efficacité du programme opération.

inline void Fun(int& a, int& b)
{
    
    
	int tmp = a;
	a = b;
	b = tmp;
}

int main()
{
    
    
	int a = 10, b = 20;
	Fun(a, b);
	return 0;
}
int main()
{
    
    
	int a = 10, b = 20;
	int tmp = a;
	a = b;
	b = tmp;
	return 0;
}

  La fonction de la fonction inline est de convertir le code ci-dessus dans le code suivant, c'est-à-dire de ne pas appeler la fonction, mais de développer le code de la fonction en place. Avez-vous trouvé que cela ressemble à ce qui se passe dans le langage C ? Oui, c'estmacro

#define Add(a,b) ((a) + (b))

  Il s'agit d'implémenter une fonction d'addition avec une macro. Nous savons que la macro est directement remplacée à la position correspondante, mais nous savons que l'opérateur a une priorité. Le remplacement direct peut entraîner une priorité incorrecte de l'opérateur et provoquer des erreurs.

Inconvénients des macros :

  1. Pas pratique pour déboguer les macros. (Parce que la phase de précompilation est remplacée)
  2. Cela conduit à une mauvaise lisibilité du code, à une mauvaise maintenabilité et à une mauvaise utilisation facile.
  3. Il n'y a pas de contrôles de sécurité de type.

Avantages des macros

  1. Il n'y a pas de contrôle strict du type.
  2. Pour appeler fréquemment de petites fonctions, il n'est pas nécessaire de créer un cadre de pile pour améliorer les performances.

  Donc, afin d'éviter ce genre d'erreur, C++ a ajouté la fonction inline inline pour résoudre ce problème. Vous n'avez pas besoin d'écrire délibérément beaucoup de parenthèses pour garantir le bon ordre d'utilisation des opérateurs.

7.1 Caractéristiques

  1. inline est un moyen d'échanger de l'espace contre du temps. Si le compilateur traite la fonction comme une fonction inline, il remplacera l'appel de la fonction par le corps de la fonction pendant la phase de compilation. Défaut : cela peut agrandir le fichier objet. Avantage : moins d'appels frais généraux, améliorer l'efficacité du fonctionnement du programme.
  2. Inline n'est qu'une suggestion pour le compilateur. Différents compilateurs peuvent avoir différents mécanismes d'implémentation en ligne. La suggestion générale est : rendre la fonction plus petite (c'est-à-dire que la fonction n'est pas très longue, il n'y a pas d'instruction exacte, cela dépend de l'implémentation interne du compilateur), non Les fonctions récursives et fréquemment appelées doivent être inline, sinon le compilateur ignorera la fonctionnalité inline. Suggestions pour inline dans la cinquième édition de "C++prime":L'inlining est juste une demande au compilateur, qui peut être ignorée par le compilateur
  3. Inline ne recommande pas la séparation de la déclaration et de la définition, ce qui entraînerait des erreurs de lien. Comme inline est développé, il n'y a pas d'adresse de fonction et le lien ne sera pas trouvé.

8. mot-clé automatique

  La signification de auto dans les débuts du C/C++ est : la variable modifiée avec auto est une variable locale avec une mémoire automatique, mais malheureusement personne ne l'a utilisée. Vous pouvez vous demander pourquoi ?
  En C++11, le comité standard a donné à auto une toute nouvelle signification : auto n'est plus un indicateur de type de stockage, mais un nouvel indicateur de type pour instruire le compilateur, et les variables déclarées par auto doivent être compilées par le compilateur dérivé de période de temps.
insérez la description de l'image ici
  C'est-à-dire que auto poussera automatiquement le type de variable, ce qui est pratique pour certains types de variables relativement longs et qui seront rencontrés plus tard.

Le rôle de typeid().name() est d'identifier le type d'une variable.

Lorsque vous utilisez auto pour définir une variable, celle-ci doit être initialisée. Au stade de la compilation, le compilateur doit déduire le type réel d'auto en fonction de l'expression d'initialisation. Par conséquent, auto n'est pas une déclaration de "type", mais un "espace réservé" lorsque le type est déclaré. Le compilateur remplacera auto par le type réel de la variable lors de la compilation.

8.1 Précautions

  Lorsque vous utilisez auto pour déclarer un type pointeur, il n'y a pas de différence entre l'utilisation de auto et auto*, mais lorsque vous utilisez auto pour déclarer un type référence, vous devez ajouter &.
insérez la description de l'image ici
  Lors de la déclaration de plusieurs variables sur la même ligne, ces variables doivent être du même type, sinon le compilateur signalera une erreur, car le compilateur ne déduit en réalité que le premier type, puis définit d'autres variables avec le type déduit.

void test_auto()
{
    
    
    auto a = 1, b = 2; 
    auto c = 3, d = 4.0;  
    // 该行代码会编译失败,因为c和d的初始化表达式类型不同
}
  1. auto ne peut pas être utilisé comme paramètre de fonction.
  2. auto ne peut pas être utilisé directement pour déclarer des tableaux.
  3. Afin d'éviter toute confusion avec auto en C++98, C++11 ne conserve que l'utilisation d'auto comme indicateur de type.
  4. L'avantage le plus courant de auto dans la pratique est de l'utiliser en conjonction avec la nouvelle boucle for fournie par C++11, qui sera mentionnée plus tard, et les expressions lambda.

9. Boucle for basée sur la plage

  Nous parcourons généralement un tableau comme celui-ci :

int main()
{
    
    
	int a[5] = {
    
     0,1,2,3,4 };
	for(int i = 0; i < 5; i++)
	{
    
    
		cout << a[i] << " ";
	}
	return 0;
}

  Pour une collection étendue, il est redondant et parfois source d'erreurs pour le programmeur de spécifier l'étendue de la boucle. Par conséquent, les boucles for basées sur la plage ont été introduites dans C++11. Les parenthèses après la boucle for sont divisées en deux parties par le signe ":": la première partie est la variable utilisée pour l'itération dans la plage, et la deuxième partie représente la plage à itérer.
insérez la description de l'image ici
  Le processus réel consiste à retirer un nombre dans arr et à le mettre dans e, à le sortir, puis à continuer pour obtenir le deuxième nombre...

9.1 Conditions d'utilisation

  1. La plage de l'itération de la boucle for doit être déterminée.
      Pour un tableau, il s'agit de la plage du premier élément et du dernier élément du tableau ; pour une classe, les méthodes de début et de fin doivent être fournies, et le début et la fin sont les plage de l'itération de la boucle for. .
void test_for(int arr[])
{
    
    
    for(auto& e : arr)
        cout<< e <<endl;
}

  Écrire de cette façon est problématique, car la portée de for est indéterminée.
2. L'objet itéré doit implémenter les opérations de ++ et ==, et c'est pour les classes.

10. Contrôle du pointeur nullptr

  Dans les bonnes pratiques de programmation C/C++, il est préférable de donner à la variable une valeur initiale appropriée lors de la déclaration d'une variable, sinon des erreurs inattendues peuvent se produire, telles que des pointeurs non initialisés. Si un pointeur n'a pas de point légal vers, nous l'initialisons essentiellement comme suit :

void test_ptr()
{
    
    
	int* p1 = NULL;
	int* p2 = 0;
	//……	
}

  NULL est en fait une macro. Dans le fichier d'en-tête C traditionnel (stddef.h), vous pouvez voir le code suivant :

#ifndef NULL
#ifdef __cplusplus
#define NULL   0
#else
#define NULL   ((void *)0)
#endif
#endif

  Comme vous pouvez le voir, NULL peut être défini comme la constante littérale 0, ou comme une constante d'un pointeur non typé (void*). Quel que soit le type de définition adopté, certains problèmes seront inévitablement rencontrés lors de l'utilisation de pointeurs de valeurs nulles, tels que :

void f(int)
{
    
    
 	cout<<"f(int)"<<endl;
}
void f(int*)
{
    
    
 	cout<<"f(int*)"<<endl;
}
int main()
{
    
    
 	f(0);
 	f(NULL);
 	f((int*)NULL);
 	return 0;
}

insérez la description de l'image ici

  L'intention originale du programme est d'appeler la version pointeur de la fonction f(int*) via f(NULL), mais comme NULL est défini comme 0, c'est contraire à l'intention originale du programme.
  En C++98, la constante littérale 0 peut être soit un nombre entier, soit une constante pointeur non typée (void*), mais le compilateur la traite par défaut comme une constante entière. Pour l'utiliser en mode pointeur, elle doit être forcée à (vide *)0.
  Par conséquent, en C++, cette situation est distinguée et nullptr est spécifiquement utilisé pour faire référence à des pointeurs.

10.1 Précautions

  1. Lors de l'utilisation de nullptr pour représenter la valeur null du pointeur, il n'est pas nécessaire d'inclure le fichier d'en-tête, car nullptr a été introduit en tant que nouveau mot-clé dans C++11.
  2. En C++11, sizeof(nullptr) et sizeof((void*)0) occupent le même nombre d'octets.
  3. Afin d'améliorer la robustesse du code, il est recommandé d'utiliser nullptr lors de la représentation ultérieure de la valeur nulle du pointeur.

11. Résumé

  Lorsque vous apprenez le C++ pour la première fois, il y a beaucoup d'endroits à mémoriser. Ce n'est pas difficile mais il y a beaucoup de détails. Il est recommandé d'organiser quelques notes pour vous aider à réviser à l'avenir.
  Le nombre de mots dans cet article est acceptable, et les débutants en C++ sont encore un peu fatigués (soupir), mais c'est bien mieux qu'avant (plaisir). Si vous trouvez quelque chose qui ne va pas, vous pouvez le signaler dans un message privé ou dans la zone de commentaire (demander humblement des conseils, demander de l'aide au patron). Je vais continuer à étudier le C++ en profondeur, et j'espère faire des progrès avec tout le monde, c'est donc la fin de ce numéro, à la prochaine ! ! Si vous vous sentez bien, vous pouvez cliquer sur un j'aime pour montrer vos encouragements ! !

Je suppose que tu aimes

Origine blog.csdn.net/qq_62321047/article/details/132257687
conseillé
Classement