Teknologian jakaminen

Ensimmäinen johdatus c:hen (nimiavaruus, oletusparametrit, toimintojen ylikuormitus)

2024-07-12

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

1. Nimiavaruus

1. Nimiavaruuden merkitys

C/C++:ssa on suuri määrä muuttujia, funktioita ja luokkia, jotka opitaan myöhemmin. Näiden muuttujien, funktioiden ja luokkien nimet ovat olemassa kaikkialla maailmassa.

Paikallisella tasolla se voi aiheuttaa monia ristiriitoja.Nimiavaruuksien käytön tarkoitus on lokalisoida tunnisteiden nimet nimeämisen välttämiseksi

Ristiriita tai nimien saastuminen, namespac-avainsana näyttää ratkaisevan tämän ongelman.

Seuraavan ohjelman kaltaiset nimeämisristiriidat C-kielen projekteissa ovat yleisiä ongelmia C++:n avulla niiden ratkaisemiseksi paremmin.

Tällainen ongelma: (Virhe ilmoitetaan, koska asettamamme muuttuja rand on ristiriidassa stdlib.h:n rand-funktion kanssa)

#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. Nimiavaruuden määritelmä

1. Määritä nimiavaruus käyttämällä nimiavaruuden avainsanaa, jota seuraa nimiavaruuden nimi, ja yhdistä sitten pari {}, jossa {}

Eli nimiavaruuden jäsen. Muuttujat/funktiot/tyypit jne. voidaan määritellä nimiavaruudessa.(Huomaa, että {}:n perässä ei ole ";")

2. Nimiavaruuden ydin on määrittää toimialue Tämä toimialue on riippumaton globaalista toimialueesta. Eri toimialueet voivat määritellä muuttujia samalla nimellä

Yllä oleva rand ei ole enää ristiriidassa.

#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. C++:n toimialueet sisältävät funktion paikallinen toimialue, globaali toimialue, nimiavaruusalue ja luokkaverkkoalue, joka vaikuttaa käännösajan syntaksiin muuttujan/funktion/ löytämiseksi;

Tyypin alkuperän logiikka (ilmoitus tai määritelmä), verkkotunnuksen eristämisellä, nimiristiriidat ratkaistaan.Sen lisäksi, että se vaikuttaa paikalliseen verkkotunnukseen ja globaaliin verkkotunnukseen

Hakulogiikan kääntäminen vaikuttaa myös muuttujan ilmoitussykliin.

4. Nimiavaruus voidaan määritellä vain globaalisti, ja tietysti se voidaan määritellä myös sisäkkäisenä.

#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. Samannimiset nimiavaruudet, jotka on määritetty useissa projektin tiedostoissa, katsotaan yhdeksi nimiavaruudeksi, eivätkä ne ole ristiriidassa.

test.c-tiedosto

#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 tiedosto

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

Voidaan havaita, että d-muuttujaa tmp-tilassa voidaan käyttää .c-tiedostossa.

6. C++-standardikirjasto sijoitetaan nimiavaruuteen nimeltä std (standardi).

7. Jos haluamme käyttää muuttujia globaalissa toimialueella, voimme tehdä näin:

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

Tällä tavalla printf tulostaa ensin 3.

3. Nimiavaruuden käyttö

Kun käännetään etsimään muuttujan ilmoitusta/määritelmää, se etsii oletusarvoisesti vain paikallisesti tai globaalisti, ei nimiavaruudesta.niin

Seuraava ohjelma kääntää ja ilmoittaa virheestä.

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

Joten meidän on käytettävä nimiavaruudessa määriteltyjä muuttujia/funktioita. On kolme tapaa:

1. Määritä nimitilan käyttöoikeus Tätä menetelmää suositellaan projektissa.

tmp::d
  • 1

2. Käyttämällä laajentaa nimiavaruuden jäsentä.Tätä lähestymistapaa suositellaan usein käyttäville projektin jäsenille, joilla ei ole konflikteja.

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. Laajenna kaikki jäsenet nimiavaruudessa,Projektia ei suositella, koska konfliktien riski on suuri. Päivittäistä harjoitusohjelmaa suositellaan mukavuuden vuoksi.

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. Tulo ja lähtö

1. Se on lyhenne sanoista Input Output Stream. Se on vakiotulo- ja lähtövirtakirjasto, joka määrittelee vakiotulon ja -lähdön.

ulos objekti.

2. std::cin on istream-luokan objekti, joka on pääasiassa suunnattu kapeiden merkkien (tyyppiä char) vakiotulostukseen.

Sisäänvirtaus.

3. std::cout on ostream-luokan objekti, joka on pääasiassa suunnattu kapeiden merkkien standardilähtövirtaan.

4. std::endl on funktio Kun virta lisätään ulostuloon, se vastaa rivinvaihdon lisäämistä ja puskurin päivittämistä.

5. &lt;&lt; on virran lisäysoperaattori ja &gt;&gt; on virran erotusoperaattori. (C-kieli käyttää myös näitä kahta operaattoria suorittamaan bittikohtaisia ​​toimintoja, kuten siirto vasemmalle/oikealle)

6. On kätevämpää käyttää C++:a syötteeseen ja ulostuloon. Ei tarvitse määrittää manuaalisesti muotoa, kuten printf/scanf, tuloa ja tulosta varten.

Tulos voi automaattisesti tunnistaa muuttujatyypit(Pohjimmiltaan tämä saavutetaan toimintojen ylikuormituksella). Itse asiassa tärkeintä on, että C++-streamit tukevat paremmin mukauttamista.

Kirjoita objektit input ja 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 jne. kuuluvat kaikki C++-standardikirjastoon. C++-standardikirjasto sijoitetaan nimiavaruuteen nimeltä std (standardi), joten se on välttämätöntä

Käytä niitä nimitilan käytön kautta.

8、⼼Voimme käyttää nimiavaruuden std:tä yleisissä päivittäisissä harjoituksissa, mutta varsinaisessa projektikehityksessä ei suositella nimiavaruuden std käyttöä.

3. Oletusparametrit

1. Oletusparametrien määritelmä ja määräykset

Oletusparametrit määrittävät oletusarvon funktion parametreille funktiota määritettäessä tai määritettäessä.Tätä funktiota kutsuttaessa, jos todellisia parametreja ei ole määritetty

Tällöin käytetään muodollisen parametrin oletusarvoa, muutoin käytetään määritettyä todellista parametria. Oletusparametrit jaetaan täydellisiin oletusparametreihin ja puolioletusparametreihin. (Joissain paikoissa,

Oletusparametreja kutsutaan myös oletusparametreiksi).

Täysi oletus tarkoittaa, että kaikille muodollisille parametreille annetaan oletusarvot, ja semi-default tarkoittaa, että joillekin muodollisille parametreille annetaan oletusarvot.C++ edellyttää, että puolioletusparametrien on oltava oikealta vasemmalle

Jatkuvat oletusasetukset peräkkäin, eikä niitä voi hypätä oletusarvoon väliajoin.

Toimintokutsuissa oletusparametreilla C++ edellyttää, että todelliset parametrit on annettava peräkkäin vasemmalta oikealle, eikä todellisia parametreja voi ohittaa.

Kun funktion määrittely ja määrittely erotetaan toisistaan, oletusparametreja ei voi esiintyä sekä funktion määrittelyssä että määrittelyssä. On säädetty, että funktio on ilmoitettava oletuksena

arvo.

#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

Lisää kuvan kuvaus tähän

2. Täysi oletus ja puolioletus

#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

Puolioletusarvoa ei voi kirjoittaa näin:

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

On ehdottomasti noudatettava:

Puolioletusparametreja on jatkuvasti asetettava oletusarvoisesti oikealta vasemmalle, eikä niitä voi hypätä oletusarvoihin aikavälein.

3. Oletusparametrien käytännön soveltaminen

Ennen kuin opimme C++:aa, kun toteutimme pinon alustuksen ja lisäyksen, kirjoitimme tämän:

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

Jos haluamme lisätä 100 dataa, tarvitsemme jatkuvaa laajennusta ja tehokasta häviötä, mutta kun olemme oppineet oletusparametrit, voimme kirjoittaa näin:

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

Tämä välttää tehokkaasti toistuvan tilan avaamisen ongelman.

4. Toimintojen ylikuormitus

C++ tukee saman nimisiä funktioita, jotka esiintyvät samassa laajuudessa, mutta edellyttävät, että näiden samannimisten funktioiden muodolliset parametrit ovat erilaisia. Tämä voi olla eri määrä parametreja tai

Eri tyypit. Tällä tavalla C++-funktiokutsut käyttäytyvät polymorfisesti ja ovat joustavampia käyttää. (Eri palautusarvoja ei kuitenkaan voida käyttää ylikuormitusolosuhteina.

Koska sitä ei voida erottaa soitettaessa, jos paluuarvo ja parametrin tyyppi tai numero muuttuvat samaan aikaan, se on myös ylikuormitustila).

1. Eri parametrityypit

#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. Parametrien määrä on erilainen

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

Erityisesti, jos yllä oleva menetelmä käyttää oletusparametreja, tulee virheilmoitus, kun kutsutaan ilman parametrien välitystä. Kääntäjä ei tiedä ketä kutsua.

// 下⾯两个函数构成重载
// 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. Parametrien järjestys on erilainen (itse asiassa parametrityypit ovat erilaisia)

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

tulos:
Lisää kuvan kuvaus tähän