Partage de technologie

Première introduction à c (espace de noms, paramètres par défaut, surcharge de fonctions)

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

1. Espace de noms

1. La signification de l'espace de noms

En C/C++, il existe un grand nombre de variables, fonctions et classes à apprendre plus tard. Les noms de ces variables, fonctions et classes existeront partout dans le monde.

Au niveau local, cela peut provoquer de nombreux conflits.Le but de l'utilisation des espaces de noms est de localiser les noms des identifiants pour éviter de nommer

Conflit ou pollution de nom, le mot-clé namespac semble résoudre ce problème.

Les conflits de noms comme le programme suivant dans les projets en langage C sont des problèmes courants. C++ introduit un espace de noms pour mieux les résoudre.

Un tel problème : (L'erreur est signalée car la variable rand que nous avons définie est en conflit avec la fonction rand dans stdlib.h)

#include <stdio.h>
#include <stdlib.h>
int rand = 10;
int main()
{
	// 编译报错:error C2365: “rand”: 重定义;以前的定义是“函数”
	printf("%dn", rand);
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

2. Définition de l'espace de noms

1. Pour définir un espace de noms, vous devez utiliser le mot-clé namespace, suivi du nom de l'espace de noms, puis connecter une paire de {}, où {}

C'est-à-dire un membre de l'espace de noms. Les variables/fonctions/types, etc. peuvent être définis dans l'espace de noms.(Notez que {} n'est pas suivi de ";")

2. L'essence de l'espace de noms est de définir un domaine. Ce domaine est indépendant du domaine global. Différents domaines peuvent définir des variables portant le même nom, donc ce qui suit.

Le rand ci-dessus n'est plus en conflit.

#include<iostream>
#include <stdio.h>
#include <stdlib.h>
namespace tmp
{
	int rand = 0;
}
int main()
{
	printf("%dn", rand);
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

3. Les domaines en C++ incluent le domaine local de fonction, le domaine global, le domaine d'espace de noms et le domaine de classe ; le domaine affecte la syntaxe de compilation pour trouver une variable/fonction/.

La logique d'origine du type (déclaration ou définition), avec l'isolation du domaine, les conflits de noms sont résolus.En plus d'affecter le domaine local et le domaine global

La logique de recherche de compilation affectera également le cycle de déclaration des variables. Les domaines d'espace de noms et les domaines de classe n'affectent pas le cycle de déclaration des variables.

4. L'espace de noms ne peut être défini que globalement et, bien sûr, il peut également être imbriqué.

#include<iostream>
#include <stdio.h>
#include <stdlib.h>
namespace tmp
{
	int rand = 0;
	namespace tmp1
	{
		int Add(int left, int right)
		{
			return left + right;
		}
		struct Node
		{
			struct Node* next;
			int val;
		};
	}

}
int main()
{
	printf("%dn", rand);
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

5. Les espaces de noms portant le même nom définis dans plusieurs fichiers du projet seront considérés comme un seul espace de noms et n'entraîneront pas de conflit.

fichier test.c

#include<iostream>
#include <stdio.h>
#include <stdlib.h>
#include"test.h"
namespace tmp
{
	int rand = 0;
	namespace tmp1
	{
		int Add(int left, int right)
		{
			return left + right;
		}
		struct Node
		{
			struct Node* next;
			int val;
		};
	}

}
int main()
{
	printf("%dn", tmp::d);
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

fichier test.h

#pragma once
namespace tmp
{
	int d = 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5

On peut constater que la variable d dans l'espace tmp peut être utilisée dans le fichier .c.

6. La bibliothèque standard C++ est placée dans un espace de noms appelé std (standard).

7. Si nous voulons utiliser des variables dans le domaine global, nous pouvons faire ceci :

int a = 3;
int main()
{
	int a = 0;
	printf("%dn", ::a);
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

De cette façon, printf en imprime 3 en premier.

3. Utilisation de l'espace de noms

Lors de la compilation pour rechercher la déclaration/définition d'une variable, par défaut, la recherche sera effectuée uniquement localement ou globalement, pas dans l'espace de noms.donc

Le programme suivant compilera et signalera une erreur.

namespace tmp
{
	int d = 0;
	namespace tmp1
	{
		int Add(int left, int right)
		{
			return left + right;
		}
		struct Node
		{
			struct Node* next;
			int val;
		};
	}
}
int main()
{
	int a = 0;
	printf("%dn", d);//未定义标识符d
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

Nous devons donc utiliser des variables/fonctions définies dans l'espace de noms. Il existe trois manières :

1. Spécifiez l'accès à l'espace de noms. Cette méthode est recommandée dans le projet.

tmp::d
  • 1

2. L'utilisation développe un membre de l'espace de noms.Cette approche est recommandée pour les membres du projet fréquemment consultés qui n’ont pas de conflits.

namespace tmp
{
	int d = 0;
	namespace tmp1
	{
		int Add(int left, int right)
		{
			return left + right;
		}
		struct Node
		{
			struct Node* next;
			int val;
		};
	}
}
using tmp::d;
int main()
{
	int a = 0;
	printf("%dn", d);//未定义标识符d
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

3. Développez tous les membres dans l'espace de noms,Le projet n'est pas recommandé car le risque de conflit est élevé. Le programme de pratique quotidienne est recommandé par commodité.

namespace tmp
{
	int d = 0;
	namespace tmp1
	{
		int Add(int left, int right)
		{
			return left + right;
		}
		struct Node
		{
			struct Node* next;
			int val;
		};
	}
}
using namespace tmp;
int main()
{
	int a = 0;
	printf("%dn", d);//未定义标识符d
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

2. Entrée et sortie

1. C'est l'abréviation de Input Output Stream. Il s'agit d'une bibliothèque de flux d'entrée et de sortie standard qui définit l'entrée et la sortie standard.

hors objet.

2. std::cin est un objet de la classe istream, qui est principalement orienté vers la sortie standard de caractères étroits (de type char).

Afflux.

3. std::cout est un objet de la classe ostream, qui est principalement orienté vers le flux de sortie standard de caractères étroits.

4. std::endl est une fonction Lorsque le flux est inséré dans la sortie, cela équivaut à insérer un caractère de nouvelle ligne et à actualiser le tampon.

5. &lt;&lt; est l'opérateur d'insertion de flux et &gt;&gt; est l'opérateur d'extraction de flux. (Le langage C utilise également ces deux opérateurs pour effectuer des opérations au niveau du bit telles que le décalage vers la gauche/le décalage vers la droite)

6. Il est plus pratique d'utiliser C++ pour l'entrée et la sortie. Il n'est pas nécessaire de spécifier manuellement le format comme printf/scanf pour l'entrée et la sortie C**++.

La sortie peut identifier automatiquement les types de variables(Essentiellement, cela est réalisé grâce à la surcharge de fonctions). En fait, le plus important est que les flux C++ peuvent mieux prendre en charge la personnalisation.

Tapez les objets d'entrée et de sortie.

#include<iostream>
#include <stdio.h>
#include <stdlib.h>
namespace tmp
{
	int a = 0;
	double b = 0.0;
	char c = '0';
	namespace tmp1
	{
		int Add(int left, int right)
		{
			return left + right;
		}
		struct Node
		{
			struct Node* next;
			int val;
		};
	}
}
using namespace tmp;
using namespace std;
int main()
{
	cin >> a >> b >> c;
	cout << a << b << c;
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

7. cout/cin/endl, etc. appartiennent tous à la bibliothèque standard C++. La bibliothèque standard C++ est placée dans un espace de noms appelé std (standard), il est donc nécessaire de le faire.

Utilisez-les via l'utilisation de l'espace de noms.

8、⼼Nous pouvons utiliser l'espace de noms std dans la pratique quotidienne générale, mais il n'est pas recommandé d'utiliser l'espace de noms std dans le développement réel d'un projet.

3. Paramètres par défaut

1. Définition et réglementation des paramètres par défaut

Les paramètres par défaut spécifient une valeur par défaut pour les paramètres 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é

Ensuite, la valeur par défaut du paramètre formel est utilisée, sinon le paramètre réel spécifié est utilisé. Les paramètres par défaut sont divisés en paramètres par défaut complets et semi-par défaut. (À certains endroits,

Les paramètres par défaut sont également appelés paramètres par défaut).

La valeur par défaut complète signifie que tous les paramètres formels reçoivent des valeurs par défaut, et la valeur par défaut semi-par défaut signifie que certains paramètres formels reçoivent des valeurs par défaut.C++ stipule que les paramètres semi-par défaut doivent être de droite à gauche

Valeurs par défaut continues dans l'ordre et ne peut pas passer à la valeur par défaut à intervalles réguliers.

Pour les appels de fonction avec des paramètres par défaut, C++ stipule que les paramètres réels doivent être donnés séquentiellement de gauche à droite et que les paramètres réels ne peuvent pas être ignorés.

Lorsque la déclaration et la définition de fonction sont séparées, les paramètres par défaut ne peuvent pas apparaître à la fois dans la déclaration et la définition de fonction. Il est stipulé que la fonction doit être déclarée par défaut.

valeur.

#include <iostream>
using namespace std;
void Func(int a = 0)
{
	cout << a << endl;
}
int main()
{
	Func(); // 没有传参时,使⽤参数的默认值
	Func(10); // 传参时,使⽤指定的实参
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

Insérer la description de l'image ici

2. Défaut complet et semi-défaut

#include <iostream>
using namespace std;
// 全缺省
void Func1(int a = 10, int b = 20, int c = 30)
{
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl << endl;
}
// 半缺省
void Func2(int a, int b = 10, int c = 20)
{
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl << endl;
}
int main()
{
	Func1();
	Func1(1);
	Func1(1, 2);
	Func1(1, 2, 3);
	Func2(100);
	Func2(100, 200);
	Func2(100, 200, 300);
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

Le semi-défaut ne peut pas être écrit comme ceci :

void Func2(int a = 10, int b, int c = 20)
{
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl << endl;
}
//或者
void Func2(int a = 10, int b, int c)
{
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl << endl;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

Doit respecter strictement :

Les paramètres semi-par défaut doivent être continuellement réglés par défaut de droite à gauche et ne peuvent pas être ignorés aux valeurs par défaut à intervalles réguliers.

3. Application pratique des paramètres par défaut

Avant d'apprendre le C++, lorsque nous avons implémenté l'initialisation et l'insertion de la pile, nous avons écrit ceci :

typedef int STDataType;
typedef struct Stack
{
	STDataType* a;
	int top;
	int capacity;
}ST;
// 栈顶
void STInit(ST* ps, int n)
{
	assert(ps);
	ps->a = (STDataType*)malloc(n * sizeof(STDataType));
	ps->top = 0;
	ps->capacity = n;
}
void STPush(ST* ps, STDataType x)
{
	assert(ps);
	// 满了, 扩容
	if (ps->top == ps->capacity)
	{
		printf("扩容n");
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity
			* 2;
		STDataType* tmp = (STDataType*)realloc(ps->a,
			newcapacity * sizeof(STDataType));
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		ps->a = tmp;
		ps->capacity = newcapacity;
	}
	ps->a[ps->top] = x;
	ps->top++;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

Si nous voulons insérer 100 éléments de données, nous aurons besoin d’une expansion continue et d’une perte efficace, mais après avoir appris les paramètres par défaut, nous pouvons écrire comme ceci :

// 栈顶
void STInit(ST* ps, int n = 4)
{
	assert(ps);
	ps->a = (STDataType*)malloc(n * sizeof(STDataType));
	ps->top = 0;
	ps->capacity = n;
}
void STPush(ST* ps, STDataType x)
{
	assert(ps);
	// 满了, 扩容
	if (ps->top == ps->capacity)
	{
		printf("扩容n");
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity
			* 2;
		STDataType* tmp = (STDataType*)realloc(ps->a,
			newcapacity * sizeof(STDataType));
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		ps->a = tmp;
		ps->capacity = newcapacity;
	}
	ps->a[ps->top] = x;
	ps->top++;
}
int main()
{
	ST a;
	STInit(&a, 100);//这里不传100也可以,因为规定必须从左到右依次给实参,不能跳跃给实参。刚好和缺省参数确定位置互补
	for (int i = 0; i < 100; i++)
	{
		STPush(&a, i);
	}
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

Cela évite efficacement le problème de l’ouverture répétée de l’espace.

4. Surcharge de fonctions

C++ prend en charge les fonctions portant le même nom apparaissant dans la même portée, mais exige que les paramètres formels de ces fonctions portant le même nom soient différents. Il peut s'agir d'un nombre de paramètres différent ou.

Différents types. De cette manière, les appels de fonctions C++ présentent un comportement polymorphe et sont plus flexibles à utiliser. (Cependant, différentes valeurs de retour ne peuvent pas être utilisées comme conditions de surcharge.

Comme il est impossible de le distinguer lors de l'appel, si la valeur de retour et le type ou le numéro du paramètre changent en même temps, il s'agit également d'une condition de surcharge).

1. Différents types de paramètres

#include<iostream>
using namespace std;
// 1、参数类型不同
int Add(int left, int right)
{
	cout << "int Add(int left, int right)" << endl;
	return left + right;
}
double Add(double left, double right)
{
	cout << "double Add(double left, double right)" << endl;
	return left + right;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

2. Le nombre de paramètres est différent

// 2、参数个数不同
void f()
{
	cout << "f()" << endl;
}
void f(int a)
{
	cout << "f(int a)" << endl;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

En particulier, si la méthode ci-dessus utilise des paramètres par défaut, une erreur sera signalée lors de l'appel sans passer de paramètres. Le compilateur ne sait pas qui appeler.

// 下⾯两个函数构成重载
// f()但是调⽤时,会报错,存在歧义,编译器不知道调⽤谁
void f1()
{
	cout << "f()" << endl;
}
void f1(int a = 10)
{
	cout << "f(int a)" << endl;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

3. L'ordre des paramètres est différent (en fait, les types de paramètres sont différents)

// 3、参数类型顺序不同
void f(int a, char b)
{
	cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{
	cout << "f(char b, int a)" << endl;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
#include<iostream>
using namespace std;
// 1、参数类型不同
int Add(int left, int right)
{
	cout << "int Add(int left, int right)" << endl;
	return left + right;
}
double Add(double left, double right)
{
	cout << "double Add(double left, double right)" << endl;
	return left + right;
}
// 2、参数个数不同
void f()
{
	cout << "f()" << endl;
}
void f(int a)
{
	cout << "f(int a)" << endl;
}
void f(int a, char b)
{
	cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{
	cout << "f(char b, int a)" << endl;
}
int main()
{
	Add(10, 20);
	Add(10.1, 20.2);
	f();
	f(10);
	f(10, 'a');
	f('a', 10);
	return 0;
}
`#include<iostream>
using namespace std;
// 1、参数类型不同
int Add(int left, int right)
{
	cout << "int Add(int left, int right)" << endl;
	return left + right;
}
double Add(double left, double right)
{
	cout << "double Add(double left, double right)" << endl;
	return left + right;
}
// 2、参数个数不同
void f()
{
	cout << "f()" << endl;
}
void f(int a)
{
	cout << "f(int a)" << endl;
}
void f(int a, char b)
{
	cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{
	cout << "f(char b, int a)" << endl;
}
int main()
{
	Add(10, 20);
	Add(10.1, 20.2);
	f();
	f(10);
	f(10, 'a');
	f('a', 10);
	return 0;
}``

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81

résultat:
Insérer la description de l'image ici