Обмен технологиями

Первое знакомство с c (пространство имен, параметры по умолчанию, перегрузка функций)

2024-07-12

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

1. Пространство имен

1. Значение пространства имен

В C/C++ существует большое количество переменных, функций и классов, которые нужно изучить позже. Имена этих переменных, функций и классов будут существовать во всем мире.

В локальной области это может вызвать множество конфликтов.Цель использования пространств имен — локализовать имена идентификаторов, чтобы избежать именования.

В случае конфликта или загрязнения имен ключевое слово namepac решает эту проблему.

Конфликты имен, подобные следующей программе в проектах на языке C, являются распространенными проблемами. В C++ для более эффективного их решения вводится пространство имен.

Такая проблема: (Сообщается об ошибке, поскольку установленная нами переменная rand конфликтует с функцией rand в 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. Определение пространства имен

1. Чтобы определить пространство имен, вам необходимо использовать ключевое слово namespace, за которым следует имя пространства имен, а затем соединить пару {}, где {}

То есть член пространства имен. Переменные/функции/типы и т. д. могут быть определены в пространстве имен.(Обратите внимание, что за {} не следует ";")

2. Суть пространства имен заключается в определении домена. Этот домен независим от глобального домена. Разные домены могут определять переменные с одинаковым именем, поэтому следующее.

Вышеупомянутый ранд больше не находится в конфликте.

#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++ включают локальный домен функции, глобальный домен, домен пространства имен и домен класса. Этот домен влияет на синтаксис времени компиляции для поиска переменной/функции/;

Логика происхождения типа (объявление или определение), при изоляции домена разрешаются конфликты имен.Помимо влияния на локальный домен и глобальный домен

Компиляция логики поиска также повлияет на цикл объявления переменных. Домены пространства имен и домены классов не влияют на цикл объявления переменных.

4. Пространство имен может быть определено только глобально и, конечно же, может быть определено и вложенным.

#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. Пространства имен с одинаковым именем, определенные в нескольких файлах проекта, будут считаться одним пространством имен и не будут конфликтовать.

файл 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

файл test.h

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

Можно обнаружить, что переменная d в пространстве tmp может использоваться в файле .c.

6. Стандартная библиотека C++ размещается в пространстве имен std (стандарт).

7. Если мы хотим использовать переменные в глобальном домене, мы можем сделать это:

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

Таким образом, printf сначала печатает 3.

3. Использование пространства имен

При компиляции для поиска объявления/определения переменной по умолчанию поиск будет осуществляться только локально или глобально, а не в пространстве имен.так

Следующая программа скомпилируется и сообщит об ошибке.

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

Поэтому нам нужно использовать переменные/функции, определенные в пространстве имен. Есть три способа:

1. Укажите доступ к пространству имен. Этот метод рекомендуется в проекте.

tmp::d
  • 1

2. Использование расширяет член пространства имен.Этот подход рекомендуется для часто посещаемых участников проекта, у которых нет конфликтов.

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. Разверните все элементы в пространстве имен,Проект не рекомендуется, поскольку высок риск конфликта. Для удобства рекомендуется программа ежедневных тренировок.

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. Ввод и вывод

1. Это аббревиатура потока ввода-вывода. Это стандартная библиотека потоков ввода и вывода, которая определяет стандартный ввод и вывод.

внешний объект.

2. std::cin — объект класса istream, ориентированный в основном на стандартный вывод узких символов (типа char).

Приток.

3. std::cout — объект класса ostream, ориентированный в основном на стандартный поток вывода узких символов.

4. std::endl — это функция. Когда поток вставляется в выходные данные, это эквивалентно вставке символа новой строки и обновлению буфера.

5. &lt;&lt; — оператор вставки потока, &gt;&gt; — оператор извлечения потока. (Язык C также использует эти два оператора для выполнения побитовых операций, таких как сдвиг влево/вправо)

6. Для ввода и вывода удобнее использовать C++. Нет необходимости вручную указывать формат типа printf/scanf для ввода и вывода C**++**.

Вывод может автоматически идентифицировать типы переменных.(По сути, это достигается за счет перегрузки функций). На самом деле, самое главное то, что потоки C++ могут лучше поддерживать настройку.

Введите объекты ввода и вывода.

#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 и т. д. все относятся к стандартной библиотеке C++. Стандартная библиотека C++ размещается в пространстве имен std (стандарт), поэтому ее необходимо указать.

Используйте их посредством использования пространства имен.

8、⼼Мы можем использовать пространство имен std в обычных повседневных упражнениях, но не рекомендуется использовать пространство имен std в реальной разработке проекта.

3. Параметры по умолчанию

1. Определение и регулирование параметров по умолчанию.

Параметры по умолчанию определяют значение по умолчанию для параметров функции при объявлении или определении функции.При вызове этой функции, если не указаны фактические параметры

Затем используется значение формального параметра по умолчанию, в противном случае используется указанный фактический параметр. Параметры по умолчанию делятся на параметры по умолчанию и полупо умолчанию. (В некоторых местах,

Параметры по умолчанию также называются параметрами по умолчанию).

Полное значение по умолчанию означает, что всем формальным параметрам присваиваются значения по умолчанию, а полустандартное означает, что некоторым формальным параметрам присваиваются значения по умолчанию.В C++ предусмотрено, что параметры полу-по умолчанию должны идти справа налево.

Непрерывные значения по умолчанию последовательно, без возможности перехода к значению по умолчанию через определенные промежутки времени.

Для вызовов функций с параметрами по умолчанию C++ предусматривает, что фактические параметры должны задаваться последовательно слева направо, и фактические параметры нельзя пропускать.

Когда объявление и определение функции разделены, параметры по умолчанию не могут присутствовать одновременно в объявлении и определении функции. Оговаривается, что функция должна быть объявлена ​​как значение по умолчанию.

ценить.

#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

Вставьте сюда описание изображения

2. Полный дефолт и полудефолт.

#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

Полу-умолчание нельзя записать так:

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

Необходимо строго соблюдать:

Параметры полуумолчания должны постоянно присваиваться значениям по умолчанию справа налево и не могут быть пропущены к значениям по умолчанию через определенные промежутки времени.

3. Практическое применение параметров по умолчанию.

Прежде чем мы начали изучать C++, когда мы реализовали инициализацию и вставку стека, мы написали это:

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

Если мы хотим вставить 100 фрагментов данных, нам потребуется непрерывное расширение и эффективная потеря, но после того, как мы узнаем параметры по умолчанию, мы можем написать так:

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

Это эффективно позволяет избежать проблемы многократного открытия пространства.

4. Перегрузка функций

C++ поддерживает функции с одинаковым именем, встречающиеся в одной области, но требует, чтобы формальные параметры этих функций с одинаковым именем были разными. Это может быть разное количество параметров или.

Различные виды. Таким образом, вызовы функций C++ демонстрируют полиморфное поведение и становятся более гибкими в использовании. (Однако разные возвращаемые значения нельзя использовать в качестве условий перегрузки.

Поскольку при вызове невозможно различить, если возвращаемое значение и тип или номер параметра изменяются одновременно, это также является состоянием перегрузки).

1. Различные типы параметров

#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. Количество параметров разное

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

В частности, если указанный выше метод использует параметры по умолчанию, при вызове без передачи параметров будет сообщено об ошибке. Компилятор не знает, кого вызывать.

// 下⾯两个函数构成重载
// 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. Порядок параметров другой (фактически типы параметров разные)

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

результат:
Вставьте сюда описание изображения