Condivisione della tecnologia

Prima introduzione a c (namespace, parametri predefiniti, sovraccarico delle funzioni)

2024-07-12

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

1. Spazio dei nomi

1. Il significato del namespace

In C/C++ ci sono un gran numero di variabili, funzioni e classi da apprendere in seguito. I nomi di queste variabili, funzioni e classi esisteranno in tutto il mondo.

Nell'ambito locale, può causare molti conflitti.Lo scopo dell'utilizzo degli spazi dei nomi è localizzare i nomi degli identificatori per evitare la denominazione

Conflitto o inquinamento dei nomi, la parola chiave namepac sembra risolvere questo problema.

I conflitti di denominazione come il seguente programma nei progetti in linguaggio C sono problemi comuni. C++ introduce namepac per risolverli meglio.

Un problema del genere: (L'errore viene segnalato perché la variabile rand che abbiamo impostato è in conflitto con la funzione rand in 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. Definizione di spazio dei nomi

1. Per definire uno spazio dei nomi, è necessario utilizzare la parola chiave namespace, seguita dal nome dello spazio dei nomi, quindi collegare una coppia di {}, dove {}

Cioè, un membro dello spazio dei nomi. Variabili/funzioni/tipi, ecc. possono essere definiti nello spazio dei nomi.(Nota che {} non è seguito da ";")

2. L'essenza del namespace è definire un dominio. Questo dominio è indipendente dal dominio globale. Diversi domini possono definire variabili con lo stesso nome, quindi quanto segue

Il rand sopra non è più in conflitto.

#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. I domini in C++ includono il dominio locale della funzione, il dominio globale, il dominio dello spazio dei nomi e il dominio della classe. Il dominio influenza la sintassi in fase di compilazione per trovare una variabile/funzione/;

La logica del tipo origine (dichiarazione o definizione), con l'isolamento del dominio, i conflitti di nome vengono risolti.Oltre a influenzare il dominio locale e il dominio globale

La compilazione della logica di ricerca influenzerà anche il ciclo di dichiarazione delle variabili. I domini dello spazio dei nomi e i domini delle classi non influiscono sul ciclo di dichiarazione delle variabili.

4. Lo spazio dei nomi può essere definito solo globalmente e ovviamente può anche essere annidato.

#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. Gli spazi dei nomi con lo stesso nome definito in più file nel progetto saranno considerati come un unico spazio dei nomi e non saranno in conflitto.

file 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

file prova.h

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

Si può scoprire che la variabile d nello spazio tmp può essere utilizzata nel file .c.

6. La libreria standard C++ viene inserita in uno spazio dei nomi chiamato std (standard).

7. Se vogliamo utilizzare variabili nel dominio globale, possiamo farlo:

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

In questo modo printf stampa prima 3.

3. Uso dello spazio dei nomi

Durante la compilazione per cercare la dichiarazione/definizione di una variabile, per impostazione predefinita la ricerca verrà eseguita solo localmente o globalmente, non nello spazio dei nomi.COSÌ

Il seguente programma compilerà e segnalerà un errore.

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

Quindi dobbiamo utilizzare variabili/funzioni definite nello spazio dei nomi. Esistono tre modi:

1. Specificare l'accesso allo spazio dei nomi Questo metodo è consigliato nel progetto.

tmp::d
  • 1

2. Utilizzando espande un membro dello spazio dei nomi.Questo approccio è consigliato per i membri del progetto a cui si accede frequentemente che non presentano conflitti.

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. Espandi tutti i membri nello spazio dei nomi,Il progetto non è consigliato perché il rischio di conflitto è elevato. Il programma di pratica quotidiana è consigliato per comodità.

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. Ingresso e uscita

1. È l'abbreviazione di Input Output Stream È una libreria di flussi di input e output standard che definisce input e output standard.

fuori oggetto.

2. std::cin è un oggetto della classe istream, che è principalmente orientato all'output standard di caratteri stretti (di tipo char).

Afflusso.

3. std::cout è un oggetto della classe ostream, che è principalmente orientato al flusso di output standard di caratteri stretti.

4. std::endl è una funzione. Quando lo stream viene inserito nell'output, equivale a inserire un carattere di nuova riga e aggiornare il buffer.

5. &lt;&lt; è l'operatore di inserimento del flusso e &gt;&gt; è l'operatore di estrazione del flusso. (Il linguaggio C utilizza questi due operatori anche per eseguire operazioni bit a bit come lo spostamento a sinistra/lo spostamento a destra)

6. È più conveniente utilizzare C++ per input e output Non è necessario specificare manualmente il formato come printf/scanf input e output C**++ input**.

L'output può identificare automaticamente i tipi di variabile(Essenzialmente, ciò si ottiene tramite l'overload delle funzioni). In effetti, la cosa più importante è che i flussi C++ possano supportare meglio la personalizzazione.

Digitare oggetti di input e output.

#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, ecc. appartengono tutti alla libreria standard C++ La libreria standard C++ è posizionata in uno spazio dei nomi chiamato std (standard), quindi è necessario

Usali attraverso l'utilizzo dello spazio dei nomi.

8、⼼Possiamo utilizzare namespace std negli esercizi quotidiani generali, ma non è consigliabile utilizzare namespace std nello sviluppo vero e proprio del progetto.

3. Parametri predefiniti

1. Definizione e regolamentazione dei parametri di default

I parametri predefiniti specificano un valore predefinito per i parametri della funzione quando si dichiara o si definisce la funzione.Quando si chiama questa funzione, se non vengono specificati parametri effettivi

Quindi viene utilizzato il valore predefinito del parametro formale, altrimenti viene utilizzato il parametro effettivo specificato. I parametri predefiniti sono suddivisi in parametri completamente predefiniti e semi-predefiniti. (In alcuni posti,

I parametri predefiniti sono anche chiamati parametri predefiniti).

Predefinito completo significa che a tutti i parametri formali vengono assegnati valori predefiniti, mentre semi-predefinito significa che ad alcuni parametri formali vengono assegnati valori predefiniti.C++ stabilisce che i parametri semipredefiniti devono essere da destra a sinistra

Impostazioni predefinite continue in sequenza e impossibile passare al valore predefinito a intervalli.

Per le chiamate di funzione con parametri predefiniti, C++ stabilisce che i parametri effettivi devono essere forniti in sequenza da sinistra a destra e che i parametri effettivi non possono essere saltati.

Quando la dichiarazione e la definizione della funzione sono separate, i parametri predefiniti non possono apparire sia nella dichiarazione che nella definizione della funzione. Si stabilisce che la funzione deve essere dichiarata come predefinita

valore.

#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

Inserisci qui la descrizione dell'immagine

2. Full default e semi-default

#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

Il semi-default non può essere scritto in questo modo:

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

Deve attenersi rigorosamente a:

I parametri semi-predefiniti devono essere impostati continuamente da destra a sinistra e non possono essere saltati ai valori predefiniti a intervalli.

3. Applicazione pratica dei parametri predefiniti

Prima di imparare il C++, quando abbiamo implementato l'inizializzazione e l'inserimento dello stack, abbiamo scritto quanto segue:

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

Se vogliamo inserire 100 dati avremo bisogno di espansione continua e perdita efficiente, ma dopo aver appreso i parametri di default possiamo scrivere così:

// 栈顶
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

Ciò evita efficacemente il problema di aprire ripetutamente lo spazio.

4. Sovraccarico di funzioni

C++ supporta funzioni con lo stesso nome che appaiono nello stesso ambito, ma richiede che i parametri formali di queste funzioni con lo stesso nome siano diversi. Può trattarsi di un numero diverso di parametri o

Tipi diversi. In questo modo, le chiamate di funzione C++ mostrano un comportamento polimorfico e sono più flessibili da utilizzare. (Tuttavia, valori restituiti diversi non possono essere utilizzati come condizioni di sovraccarico.

Poiché non è possibile distinguerlo durante la chiamata, se il valore restituito e il tipo o il numero del parametro cambiano contemporaneamente, si tratta anche di una condizione di sovraccarico).

1. Diversi tipi di parametri

#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. Il numero di parametri è diverso

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

In particolare, se il metodo precedente utilizza parametri predefiniti, verrà segnalato un errore quando si chiama senza passare parametri. Il compilatore non sa chi chiamare.

// 下⾯两个函数构成重载
// 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'ordine dei parametri è diverso (in realtà i tipi di parametri sono diversi)

// 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

risultato:
Inserisci qui la descrizione dell'immagine