Technologieaustausch

Erste Einführung in c (Namespace, Standardparameter, Funktionsüberladung)

2024-07-12

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

1. Namensraum

1. Die Bedeutung des Namespace

In C/C++ gibt es eine große Anzahl von Variablen, Funktionen und Klassen, die später erlernt werden müssen. Die Namen dieser Variablen, Funktionen und Klassen werden auf der ganzen Welt existieren.

Im lokalen Bereich kann es zu vielen Konflikten kommen.Der Zweck der Verwendung von Namespaces besteht darin, die Namen von Bezeichnern zu lokalisieren, um eine Benennung zu vermeiden

Bei Konflikten oder Namensverschmutzung scheint das Schlüsselwort „namespac“ dieses Problem zu lösen.

Namenskonflikte wie das folgende Programm in C-Sprachprojekten sind häufige Probleme. C++ führt Namespace ein, um sie besser zu lösen.

Ein solches Problem: (Der Fehler wird gemeldet, weil die von uns festgelegte Variable rand mit der Rand-Funktion in stdlib.h in Konflikt steht.)

#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. Definition des Namensraums

1. Um einen Namespace zu definieren, müssen Sie das Schlüsselwort namespace verwenden, gefolgt vom Namen des Namespace, und dann ein Paar {} verbinden, wobei {}

Das heißt, ein Mitglied des Namespace. Im Namensraum können Variablen/Funktionen/Typen etc. definiert werden.(Beachten Sie, dass auf {} kein „;“ folgt.)

2. Der Kern des Namespace besteht darin, eine Domäne zu definieren, die unabhängig von der globalen Domäne ist. Verschiedene Domänen können Variablen mit demselben Namen definieren

Der oben genannte Rand steht nicht mehr in Konflikt.

#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. Zu den Domänen in C++ gehören die lokale Funktionsdomäne, die globale Domäne, die Namespace-Domäne und die Klassendomäne. Die Domäne beeinflusst die Syntax zur Kompilierungszeit, um eine Variable/Funktion/zu finden.

Die Logik des Typursprungs (Deklaration oder Definition) mit Domänenisolation löst Namenskonflikte.Zusätzlich zur Auswirkung auf die lokale Domäne und die globale Domäne

Das Kompilieren der Suchlogik wirkt sich auch auf den Variablendeklarationszyklus aus. Namespace-Domänen und Klassendomänen haben keinen Einfluss auf den Variablendeklarationszyklus.

4. Der Namespace kann nur global definiert werden und kann natürlich auch verschachtelt definiert werden.

#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. Namespaces mit demselben Namen, die in mehreren Dateien im Projekt definiert sind, werden als ein Namespace betrachtet und stehen nicht in Konflikt.

test.c-Datei

#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

test.h-Datei

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

Es kann festgestellt werden, dass die d-Variable im tmp-Bereich in der .c-Datei verwendet werden kann.

6. Die C++-Standardbibliothek wird in einem Namensraum namens std (Standard) abgelegt.

7. Wenn wir Variablen im globalen Bereich verwenden möchten, können wir Folgendes tun:

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

Auf diese Weise druckt printf zuerst 3.

3. Verwendung des Namensraums

Beim Kompilieren zur Suche nach der Deklaration/Definition einer Variablen wird standardmäßig nur lokal oder global gesucht, nicht im Namespace.Also

Das folgende Programm kompiliert und meldet einen Fehler.

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

Wir müssen also im Namespace definierte Variablen/Funktionen verwenden. Es gibt drei Möglichkeiten:

1. Geben Sie den Namespace-Zugriff an. Diese Methode wird im Projekt empfohlen.

tmp::d
  • 1

2. Mit wird ein Mitglied des Namespace erweitert.Dieser Ansatz wird für Mitglieder des Projekts empfohlen, auf die häufig zugegriffen wird und die keine Konflikte haben.

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. Erweitern Sie alle Mitglieder im Namespace.Das Projekt wird nicht empfohlen, da das Konfliktrisiko hoch ist. Das tägliche Übungsprogramm wird aus Bequemlichkeitsgründen empfohlen.

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. Eingabe und Ausgabe

1. Es ist die Abkürzung für Input Output Stream. Es handelt sich um eine Standard-Eingabe- und Ausgabe-Stream-Bibliothek, die Standard-Eingabe und -Ausgabe definiert.

aus Objekt.

2. std::cin ist ein Objekt der istream-Klasse, das hauptsächlich auf die Standardausgabe schmaler Zeichen (vom Typ char) ausgerichtet ist.

Zufluss.

3. std::cout ist ein Objekt der Klasse ostream, das hauptsächlich auf den Standardausgabestrom schmaler Zeichen ausgerichtet ist.

4. std::endl ist eine Funktion. Wenn der Stream in die Ausgabe eingefügt wird, entspricht dies dem Einfügen eines Zeilenumbruchzeichens und dem Aktualisieren des Puffers.

5. &lt;&lt; ist der Stream-Einfügungsoperator und &gt;&gt; ist der Stream-Extraktionsoperator. (Die C-Sprache verwendet diese beiden Operatoren auch, um bitweise Operationen wie Linksverschiebung/Rechtsverschiebung durchzuführen.)

6. Es ist bequemer, C++ für die Eingabe und Ausgabe zu verwenden. Es ist nicht erforderlich, das Format wie printf/scanf für die Eingabe und Ausgabe in C**** festzulegen.

Die Ausgabe kann Variablentypen automatisch identifizieren(Im Wesentlichen wird dies durch Funktionsüberladung erreicht.) Das Wichtigste ist tatsächlich, dass C++-Streams die Anpassung besser unterstützen können.

Geben Sie Objekte ein und geben Sie sie aus.

#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 usw. gehören alle zur C++-Standardbibliothek. Die C++-Standardbibliothek befindet sich in einem Namespace namens std (Standard), daher ist dies erforderlich

Nutzen Sie sie über die Namespace-Nutzung.

8、⼼Wir können Namespace std in allgemeinen täglichen Übungen verwenden, es wird jedoch nicht empfohlen, Namespace std in der tatsächlichen Projektentwicklung zu verwenden.

3. Standardparameter

1. Definition und Regelung von Standardparametern

Standardparameter geben einen Standardwert für die Parameter der Funktion an, wenn die Funktion deklariert oder definiert wird.Beim Aufruf dieser Funktion werden keine Aktualparameter angegeben

Dann wird der Standardwert des formalen Parameters verwendet, andernfalls wird der angegebene Aktualparameter verwendet. Die Standardparameter werden in vollständige Standard- und Semi-Standardparameter unterteilt. (An manchen Orten

Standardparameter werden auch als Standardparameter bezeichnet.

Vollständiger Standard bedeutet, dass alle formalen Parameter Standardwerte erhalten, und halber Standard bedeutet, dass einige formale Parameter Standardwerte erhalten.C++ schreibt vor, dass Semi-Standard-Parameter von rechts nach links sein müssen

Kontinuierlich wird der Reihe nach voreingestellt, und es ist nicht möglich, in bestimmten Abständen zum Standardwert zu springen.

Für Funktionsaufrufe mit Standardparametern schreibt C++ vor, dass tatsächliche Parameter der Reihe nach von links nach rechts angegeben werden müssen und tatsächliche Parameter nicht übersprungen werden können.

Wenn Funktionsdeklaration und -definition getrennt sind, können Standardparameter nicht sowohl in der Funktionsdeklaration als auch in der Definition erscheinen. Es wird festgelegt, dass die Funktion als Standard deklariert werden muss

Wert.

#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

Fügen Sie hier eine Bildbeschreibung ein

2. Vollständiger Standard und halber Standard

#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

Semi-Default kann nicht so geschrieben werden:

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

Muss strikt eingehalten werden:

Semi-Standardparameter müssen kontinuierlich von rechts nach links standardmäßig voreingestellt werden und können nicht in Intervallen auf Standardwerte zurückgesetzt werden.

3. Praktische Anwendung von Standardparametern

Bevor wir C++ lernten, schrieben wir Folgendes, als wir die Stapelinitialisierung und -einfügung implementierten:

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

Wenn wir 100 Daten einfügen möchten, benötigen wir eine kontinuierliche Erweiterung und einen effizienten Verlust. Nachdem wir jedoch die Standardparameter kennengelernt haben, können wir Folgendes schreiben:

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

Dadurch wird das Problem der wiederholten Freilegung von Platz effektiv vermieden.

4. Funktionsüberlastung

C++ unterstützt Funktionen mit demselben Namen, die im selben Bereich erscheinen, erfordert jedoch, dass die formalen Parameter dieser Funktionen mit demselben Namen unterschiedlich sind. Dies kann eine unterschiedliche Anzahl von Parametern sein

Verschiedene Typen. Auf diese Weise weisen C++-Funktionsaufrufe ein polymorphes Verhalten auf und sind flexibler in der Verwendung. (Abweichende Rückgabewerte können jedoch nicht als Überlastbedingungen verwendet werden.

Da es beim Aufruf nicht unterschieden werden kann, handelt es sich auch um eine Überlastungsbedingung, wenn sich der Rückgabewert und der Parametertyp oder die Parameternummer gleichzeitig ändern.

1. Verschiedene Parametertypen

#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. Die Anzahl der Parameter ist unterschiedlich

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

Insbesondere wenn die obige Methode Standardparameter verwendet, wird beim Aufruf ohne Übergabe von Parametern ein Fehler gemeldet. Der Compiler weiß nicht, wen er aufrufen soll.

// 下⾯两个函数构成重载
// 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. Die Reihenfolge der Parameter ist unterschiedlich (eigentlich sind die Parametertypen unterschiedlich).

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

Ergebnis:
Fügen Sie hier eine Bildbeschreibung ein