‘호출자의 코드만 보고서는 절대로 함수의 원형을 정확히 알아낼 수 없다’
Chapter 02. C++ 함수와 네임스페이스
핵심 개념
1. 디폴트 매개변수
2. 다중 정의
3. 인라인 함수
4. 네임스페이스
학습 목표: c++의 효율성
1. 매개변수 없이도 함수를 자유롭게 사용하는 방법
2. Add() 함수를 얼마나 다양한 형태로 사용할 수 있는가
3. 변수, 함수 등 하나로 묶는 법
4. 네임스페이스의 간결성
1. 디폴트 매개변수
- 정의: 매개변수가 필요한 함수에서 매개변수에 초기값을 주어 호출자가 실인수를 기입하지 않아도 해당 매개변수에 초기값이 입력되어 실행되는 것
- 기본 형태: [반환자료형 함수이름(매개변수 자료형 이름 = 디폴트 값)]
- 주의할 점
n 매개변수의 디폴트 값은 반드시 함수 원형의 선언 부분에 기술해야 함
n 매개변수의 디폴트 값은 우측부터 지정한다.
n 호출자 함수가 실인수를 기술할 때, 왼쪽부터 짝을 맞춘다.
n 디폴트 매개변수를 남발할 경우 함수의 모호성을 가져옴
- 활용도
n 코드를 수정할 때 가급적 함수 원형을 수정하지 않는 것이 좋음
u 디폴트 매개변수를 사용해서 원형 함수를 만드는 것이 좋음
2. 함수 다중 정의(Overloading)
- 정의: 함수 이름은 같으나 여러 의미를 갖는 것
- 형태 예시
n Int Add(int, int) / double Add(double, double)
n Int Add(5, 4) / double Add(1.1, 2.2) etc..
- 다중 정의에 영향을 주는 것은 ‘매개변수’이다.
- 주의사항
n 반환 형식만 다를 경우 에러
int Add(int a, int b); double Add(int a, int b); |
n 호출 규칙만 다를 경우 에러
int __cdecl Add(int a, int b); int __stdcall Add(int a, int b); |
__stdcall (standard call) : 함수가 규약되어 있으면 함수를 호출한 쪽에서 parameter값들을 함수가 return 되고 난 후 stack 에서 제거한다. 호출한 함수가 자신의 parameter값을 알고 있기 때문에 가변적인 함수에서 사용가능하다.
__cdecl (C delcaration) : 함수를 호출받은 쪽(함수의 내부)에서 parameter를 제거하게 되어있습니다. 그렇기 때문에 parameter의 개수가 명확한 곳에서 사용된다. 보통 WinAPI가 함수에 따른 인자들이 명확히 정의되어있어 이 규약을 사용한다. [출처] C++ __stdcall 과 __cdecl의 차이점_오늘의 공부|작성자 박경준 |
n 디폴트 매개변수와 다중 정의 함수가 만날 경우 모호성이 커진다.
u 호출자가 함수를 호출할 때, 다중 정의된 함수가 2개 이상 값을 처리할 수 있을 때 함수가 모호함.
u Ex) void TestFunc(int a); / void TestFunc(int a, int b = 10); => TestFunc(5)
- 템플릿
n 정의: 매개변수의 타입에 따라 함수나 클래스를 생성하는 메커니즘
n 다중 정의를 사용하는 것보다 템플릿을 사용하는 것이 효율적
n 다중 정의 함수를 불필요하게 사용하게 되면 코드길이가 늘어나고, 메모리 낭비 비효율적 따라서, 템플릿을 사용하는 것을 권함
n 기본 형태: template <typename T>
n 사용자 코드에 의해 컴파일러가 알아서 다중 정의 코드를 생성
n 만일 사용자가 함수를 사용하지 않을 경우 아무런 코드가 생성되지 않음
3. 인라인 함수
- 함수 vs 매크로
#define |
Function |
- 전처리기 영역에서 단순 치환 - 컴파일 과정에서 발생하는 데이터 타입에 관한 문제 발견 못함 - 다양한 논리적 오류 발생 - 매개변수에 형식 지정 불가 |
- 프로그램을 작은 크기의 함수들로 나눠서 구현하기 위함 (윤성우 열혈 c프로그래밍) - 스택 메모리 사용 증가 - 제어 흐름 이동으로 인한 연산 증가 |
- Inline 함수: 위 함수, 매크로의 단점을 보완하기 위한 것
- 외적으로 함수 모양이나, 내부적으로는 함수 호출을 하지 않는다.
- 코드 길이가 일정 수준 이상일 경우 인라인 함수가 되는 것은 옳지 않다.
n 이는 컴파일러가 결정
4. 네임스페이스
- 각종 요소들을 한 범주로 묶어 주기 위한 문법(집합, 소속, 구역의 개념)
- 기본 형태: namespace 이름 { }
- 지정 연산자(::) : 네임스페이스에 있는 요소를 사용하기 위해 사용
- 각 네임스페이스에 있는 요소의 이름이 중복될 경우 구분 가능
- Using 예약어: 네임스페이스를 생략하기 위한 예약어
- 네임스페이스 중첩
n 네임스페이스 안에 다른 네임스페이스가 속할 수 있다.
n 이 또한 지정 연산자로 접근한다.
n 서울시::강남구::대치동::….
- 다중 정의: 네임스페이스가 다르면 이름이 같아도 무관
n 두 함수가 동명이인 같은 느낌
- 두 개의 네임스페이스가 같은 이름과 같은 매개변수를 가진 함수를 가질 때
n Using 예약어를 쓰면 호출이 모호하므로 에러 발생
n 지정 연산자로 구분해주면 해결된다.
5. 식별자 검색 순서
A. 전역 함수
1) 현재 블록 범위
2) 현재 블록 범위를 포함하고 있는 상위 블록 범위(최대 적용 범위: 함수 몸체까지)
3) 가장 최근에 선언된 전역 변수나 함수
4) Using 선언된 네임스페이스 혹은 전역 네임스페이스
B. 클래스 메서드
1) 현재 블록 범위
2) 현재 블록 범위를 포함하고 있는 상위 블록 범위(최대 적용 범위: 함수 몸체까지)
3) 클래스의 멤버
4) 부모 클래스의 멤버
5) 가장 최근에 선언된 전역 변수나 함수
6) 호출자 코드가 속한 네임스페이스의 상위 네임스페이스
7) Using 선언된 네임스페이스 혹은 전역 네임스페이스
- 식별자 검색은 기본적으로 위로 검색한다.
- 현재 블록 범위
n 현재 블록 {} 내에서 가장 최근 선언된 함수나 변수를 찾아간다.
- 상위 블록 범위
n 현재 블록에서 못 찾을 경우 상위 블록으로 찾는다
n 최대 확장 범위는 함수 몸체까지이다.
- 가장 최근에 선언된 전역 변수
n 전역 변수는 네임스페이스보다 선언 위치가 더 우선이다.
n 전역 변수는 네임스페이스를 생각하지 말고 선언 순서를 생각해야함
- Using 선언과 전역변수
n 전역변수와 using을 이용한 namespace 내 변수와 이름이 같을 경우
n 그 변수는 모호한 표현이 된다. 따라서 지정 연산자로 구체적으로 표현한다.
2장 연습문제
1. 디폴트 매개변수가 왼쪽부터 채워졌으면 끝까지 디폴트 매개변수가 선언되어야 한다.
디폴트 매개변수는 우측부터 순서대로 채워야 한다.
2. 호출자가 TestFunc(5)를 선언하게 될 경우 함수 호출이 모호하다.
첫 번째 함수는 하나의 매개변수를 받고, 두 번째 함수는 하나의 일반 매개변수를 받고, 하나의 디폴트 매개변수를 받는다.
호출자가 하나의 실인수를 넘기게 될 경우 첫 번째 함수와 두 번째 함수 모두를 선언할 수 있으므로 모호하다.
3. 다중 정의 함수를 불필요하게 사용하게 되면 코드길이가 늘어나고
함수가 차지하고 있는 메모리를 낭비하게 된다.
Template을 이용하여 컴파일러가 다중 정의 함수를 선언하게 하고, 만일 함수를 선언하지 않을 경우 아무런 코드를 생성하지 않아 효율적이다.
4. 내부적으로 함수호출을 하지 않아 빠르게 처리가 가능하다.
5. using
6. 100을 출력할 것이다.
namespece안에 있는 함수 TestFunc에서 호출한 변수 nData를 출력하는데, TestFunc에서 가장 최근에 선언한 변수는 int nData = 100; 이기 때문이다.
또한 상위 블록 범위가 int nData = 100; 이기도 하다.
1장 연습문제
1.
#include<iostream>
int main() { std::string name; std::string age; std::cin >> name >> age; std::cout <<"나의 이름은 "<<name<< "이고, "<<age<<"살입니다."<< std::endl; return 0; } |
2. Auto: 초기값의 형식에 맞춰 선언하는 인스턴스 형식이 ‘자동’으로 결정
For(auto 요소변수 : 배열 이름)
3. Char *arr = new char[12]
Delete[] arr;
4. void Swap(int& a, int& b) {
int temp = a;
a = b;
b = temp;
5. 상수에는 참조자 선언을 할 수 없다.
6. int aList[5]={10, 20, 30, 40, 50}
for (auto& n : aList) {
std::cout << n << endl;
}
'C++ > 이것이 C++이다.' 카테고리의 다른 글
Ch7. 상속 심화 (0) | 2021.01.15 |
---|---|
Ch6. 상속 기본 (0) | 2021.01.15 |
Ch5. 연산자 다중정의 (0) | 2021.01.15 |
Ch4. 복사 생성자와 임시 객체 (0) | 2021.01.15 |
Ch3. 클래스 (0) | 2021.01.15 |
최근댓글