C에서 C++ 문법 전환하기_2
Chapter.2 C++ 함수와 네임스페이스
- 디폴트 매개변수
- C에서는 함수를 호출하려 한다면 매개변수의 실 인수를 기술해야한다
- C++에서는 매개변수의 초깃값을 설정해서 입력이 없을 경우 초깃값을 대입해 준다
- 따라서 호출자를 보고 함수의 원형을 확정하면 안됨!!
- ex) int TestFunc(int nParam = 10) // = int TestFunc(int = 10)
- 이때 함수 원형의 선언 부분에 기술해야하고, 정의 부분에 기술하면 컴파일 오류가 발생한다 // 선언부분 변수 이름 생략 가능
- 매개변수 선언시 규칙
- 피호출자 함수 매개변수의 디폴트 값은 반드시 오른쪽 매개변수 부터 기술해야 한다
- 매개변수가 여려 개일 때 왼쪽 첫번째 매개변수의 디폴트 값을 기술하려면 나머지 오를쪽 모든 매개변수에 대한 디폴트 값을 기술해야 하며, 절대로 중간에 빼먹으면 안된다!
- 호출자 함수가 피호출자 함수 매개변수의 실인수를 기술하면 이는 왼쪽부터 짝을 맞추어 적용되며, 짝이 맞지 않은경우 매개변수는 디폴트 값을 적용한다
- 모호성을 조심할 것, 가급적 디폴트 매개변수 사용을 지양할 것
- 함수의 다중 정의
- 다중정의, Overloading 은 함수의 다형성을 지원(편의성, 확장성)
- 함수의 구성 요소 = 반환형식 호출규칙 함수이름(매개변수, 매개변수 ...);
- 이때 다중정의, 오버로딩을 하기 위해선 매개변수를 제외한 모든 것은 동일해야 한다!!
- 다중정의의 모호성
- 다중정의와 디폴트 매개변수가 조합되면 '모호성'이 발생할 수 있다
- ex) void TestF(int a) { ~ } / void testF(int a, int b = 10) { }
- 이때 TestF(5); 를 선언한다면 컴파일 오류가 발생한다( 모호성 때문)
- 다중정의와 디폴트 매개변수가 조합되면 '모호성'이 발생할 수 있다
- 함수 템플릿(template)
- 오버로딩으로 여러 함수를 만들기 보다 템플릿으로 만드는 것이 더 효율적이다
- 템플릿은 일종의 '틀' / 함수를 찍어내기 위한
- ex) template <typename T> / T TestFunc(T a) { } // T는 자료형
- 이때 testFunc을 호출하는 매개변수(실인수)의 자료형에 따라 T가 정해진다!
- 인라인 함수(inline)
- 인라인 함수 = (함수의 장점 + 매크로(#define) 의 장점) 이다
- 함수의 원형 앞에 inline 예약어만 작성하면 된다
- ex) inline int TestFunc(int a) { ~ }
- 코드가 일정 수준 이상으로 길어지면 인라인 함수보다 그냥 함수가 더 효율적
- 이는 컴파일러가 판단하여 인라인함수 <-> 일반 함수 로 바꿔서 컴파일 할 수 있다
- 네임스페이스(namespace)
- C++가 지원하는 각종 요소들(변수, 함수, 클래스 등)을 한 범주로 묶어주기 위한 문법
- 소속, 구역 등으로 이해 (이름의 성 같은 존재)
- 네임스페이스 선언 : namespace 이름 { ~ } // ~ 안에 변수, 함수, 클래스 가 들어갈 수 있다
- 네임스페이스의 중복 선언이 가능하다
- 네임스페이스가 없는 함수는 '전역 네임스페이스'에 속한다
- using 선언
- namespace를 생략하기 위한 예약어
- using namespace std; // std::cin 이라고 호출해야 했던 함수를 cin 으로도 호출할 수 있게 해줌
- namespace를 생략하기 위한 예약어
- 같은 함수, 변수 등 이어도 namespace가 다르면 전혀 다른 개체로 인식된다
- 네임스페이스와 다중정의
- 다중 정의의 조건은 이름이 같아야 한다, 이때 이름이 같다는 것은 namespace도 같다는 뜻을 포함한다
- 이름이 같고, 모든것이 같아도 namespace가 다르면 다른 개체! // 이때 호출시 네임스페이스를 구별해 주지 않으면 모호성에 의해 컴파일 오류가 발생한다
- 식별자 검색 순서
- 식별자가 선언된 위치를 검색하는 순서 // 이때 호출자보다 먼저 선언되야 함(윗줄에 존재해야함)
- 전역 함수읜 경우
- 현재 블록 범위
- 현재 블록 범위를 포함하고 있는 상위 블록 범위(Max는 함수 몸체)
- 가장 최근에 선언된 전역변수 나 함수
- using 선언된 네임스페이스 혹은 전역 네임스페이스 / 이때 두 곳에 동일한 식별자 존재 시 컴파일 요류
- 클래스 메서드인 경우
- 현재 블록 범위
- 현재 블록 범위를 포함하고 있는 상위 블록 범위(Max는 함수 몸체)
- 클래스의 멤버
- 부모 클래스의 멤버
- 가장 최근에 선언된 전역 변수나 함수
- 호출자 코드가 속한 네임스페이스의 상위 네임스페이스
- using 선언된 네임스페이스 혹은 전역 네임스페이스 / 이때 두 곳에 동일한 식별자 존재 시 컴파일 요류
- 다중정의, Overloading 은 함수의 다형성을 지원(편의성, 확장성)
연습문제
1. 다음 두 함수 원형에서 잘못된 점은 무엇인지 답하세요
- int TestFunc(int nParam1 = 5, int nParam2, int nParam3 = 10)
- int TestFunc(int nParam1 = 5, int nParam2)
= 초깃값 설정은 오른쪽부터, 중간에 빼먹을 수 없음
2. 다음 두 함수를 호출하는 코드에서 문제가 발생하는 이유
void TestFunc(int a) { std::cout << "TestFunc(int)" << std::endl; }
void TestFunc(int a, int b = 10) { std::cout << "TestFunc(int, int)" << std::endl; }
= 함수의 모호성이 발생하기 때문( TestFunc(10) 실행시 모호성 오류 발생 )
3. 함수를 다중정의 하는것보다 템플릿이 더 좋은 코드가 될 가능성이 높은 이유?
= 템플릿으로 함수를 작성하면 유지보수 및 관리가 쉬워진다(다중정의는 N개를 바꿔야함, 템플릿은 하나만 바꾸면 됨)
4. inline 함수와 매크로의 공통된 장점
= 대입한다( 메모리 사용량이 낮아진다 )
5. 네임스페이스 미리 선언하는 법
= using namespace
6. 다음 코드의 실행결과
#include <iostream>
using namespace std;
int nData = 200;
namespace Test {
int nData = 100;
void TestFunc(void) {
cout << nData << endl; // 여기서의 nData가 가리키는 것은? 1은 없음, 2로 100
}
}
int _tmain(int argc, _TCHAR* argv[]) {
TEST::TestFunc(); // 연산자 찾기
return 0;
}
= 100