기술나눔

c에 대한 첫 소개(네임스페이스, 기본 매개변수, 함수 오버로딩)

2024-07-12

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

1. 네임스페이스

1. 네임스페이스의 의미

C/C++에는 나중에 학습해야 할 수많은 변수, 함수, 클래스가 있습니다. 이러한 변수, 함수, 클래스의 이름은 전 세계에 존재하게 됩니다.

로컬 범위에서는 많은 충돌이 발생할 수 있습니다.네임스페이스를 사용하는 목적은 이름 지정을 피하기 위해 식별자 이름을 지역화하는 것입니다.

충돌이나 이름 오염, namespac 키워드가 이 문제를 해결하는 것으로 보입니다.

C 언어 프로젝트에서 다음 프로그램과 같은 이름 지정 충돌은 일반적인 문제입니다. C++에서는 이를 더 잘 해결하기 위해 namespac을 도입합니다.

이러한 문제: (우리가 설정한 변수 rand가 stdlib.h의 rand 함수와 충돌하기 때문에 오류가 보고됩니다.)

#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. 네임스페이스를 정의하려면 네임스페이스 키워드와 네임스페이스 이름을 차례로 사용한 다음 {} 쌍을 연결해야 합니다. 여기서 {}

즉, 네임스페이스의 멤버입니다. 네임스페이스에는 변수/함수/유형 등을 정의할 수 있습니다.({} 뒤에 ";"가 오지 않는다는 점에 유의하세요)

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

.c 파일에서는 tmp 공간의 d 변수를 사용할 수 있음을 알 수 있다.

6. C++ 표준 라이브러리는 std(standard)라는 네임스페이스에 배치됩니다.

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. 입출력 스트림(Input Output Stream)의 약자로 표준 입출력을 정의하는 표준 입출력 스트림 라이브러리이다.

아웃 개체.

2. std::cin은 istream 클래스의 객체로, 주로 char 유형의 좁은 문자의 표준 출력을 지향합니다.

유입.

3. std::cout은 주로 좁은 문자의 표준 출력 스트림을 지향하는 ostream 클래스의 객체입니다.

4. std::endl은 함수입니다. 스트림이 출력에 삽입되면 개행 문자를 삽입하고 버퍼를 새로 고치는 것과 같습니다.

5. &lt;&lt;는 스트림 삽입 연산자이고 &gt;&gt;는 스트림 추출 연산자입니다. (C 언어도 이 두 연산자를 사용하여 왼쪽 시프트/오른쪽 시프트와 같은 비트 단위 연산을 수행합니다.)

6. 입력 및 출력에 C++를 사용하는 것이 더 편리합니다. C**++ 입력**에는 printf/scanf와 같은 형식을 수동으로 지정할 필요가 없습니다.

출력은 변수 유형을 자동으로 식별할 수 있습니다.(본질적으로 이는 함수 오버로딩을 통해 달성됩니다.) 실제로 가장 중요한 것은 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(standard)라는 네임스페이스에 위치하므로 다음을 수행해야 합니다.

네임스페이스 사용을 통해 사용하세요.

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

결과:
여기에 이미지 설명을 삽입하세요.