dev_eun

[C++] ② 함수와 네임스페이스 본문

공부/C++

[C++] ② 함수와 네임스페이스

_eun 2020. 8. 31. 03:00

[Chapter 2] C++ 함수와 네임스페이스

용어

overloading : 다중 정의, 함수 이름은 같지만 매개변수의 구성이 달라 함수가 구분되는 것
inline : 함수 호출이 아닌 함수의 코드 자체가 들어가게 해주는 예약어
namespace : c++이 지원하는 각종 요소들(변수, 함수, 클래스)을 한 범주로 묶어주기 위한 문법
using : namespace를 생략할 수 있도록 사용하는 예약어


디폴트 매개변수

매개변수의 디폴트 값을 선언한 함수는 호출자 코드에서 실인수를 생략한 채 호출할 수 있다. 다만 함수의 정의가 아니라 선언 부분에 디폴트 값을 기술해야 한다.
모호성이 발생한다.

int TestFunc(int p = 10); // 컴파일 에러
int TestFunc(int = 10);

int main(){
    cout<<TestFunc(20)<<endl;
}

int TestFunc(int nParam){
    return nParam;
}

주의할 사항

  • 매개변수의 디폴트 값은 반드시 오른쪽 매개변수부터 기술해야 한다.
  • 매개변수가 여러 개일 때 디폴트 값을 기술한 매개변수부터 오른쪽 모든 매개변수들은 디폴트 값을 기술해야 한다.
  • 호출자 함수에서 매개변수를 왼쪽부터 입력하고, 입력되지 않은 나머지는 피호출자 함수의 디폴트 값이 적용된다.

함수 다중 정의

한 가지 개념을 여러 가지 형태로 다양하게 구현할 수 있다.
함수 원형의 구성 중(반환 형식, 호출 규칙, 함수 읾, 매개변수 구성) 다중 정의에 영향을 줄 수 있는 것은 매개 변수뿐이다.
모호성이 발생한다.

모호성

함수를 만든 제작자는 오류를 경험하지 않지만 함수 사용자는 오류를 경험할 수 있다

모호성의 안좋은 예

void func(int a){
    cout<<"func(int)\n";
}

void func(int a, int b = 10){
    cout<<"func(int, int)\n";
}

void main(){
    func(5);
    return 0;
}

==> 컴파일 에러 "호출이 모호합니다"

  1. main() 함수의 func(5)를 지우면 에러 안남 -> 오버로딩이 컴파일에는 문제 없음
  2. func(5,2) 호출자 함수를 사용하면 에러 안남 -> func(int, int) 함수 호출

❗️사용자는 절.대 func(int) 함수를 호출할 수 없다.

함수 템플릿

함수의 유지 보수와 확장성을 위해 템플릿 사용 권고

template <typename T>
T Add(T a, T b){
    return a+b;
}

int main(){
    cout << Add(3, 4) << '\n';
    cout << Add(3.4, 4.5) << '\n';
}

❔ 직접 형식을 지정하려면

cout << Add<int>(3,4) << '\n';

인라인 함수

함수를 호출하게 되면 스택에 쌓임 -> 여러 번 호출하면 속도 저하 가능성 높아짐
인라인 함수는 매크로의 장점과 함수의 장점을 모두 갖춘 함수이다. inline 예약어를 통해 만들어지며 함수 호출이 아닌 코드 그 자체가 들어가게 된다.

inline int AddNew(int a, int b){
    return a+b;
}

모든 함수를 인라인 함수로 만들어 버리면 코드의 길이가 길어지기 때문에 좋지 않다.


namespace

여러 사람이 공동으로 작업할 때 변수나 함수 이름이 겹치는 것을 방지할 수 있다.
c++에서 namespace에 속하지 않는 식별자는 없다. 적어도 전역 네임스페이스에 속한다.

namespace 선언

namespace TEST
{
    int testData = 10;

    void testFunc(void){
        cout << "TEST::testFunc()\n";
    }

    int main(){
        TEST::testFunc();
        cout<<TEST::testData<<'\n';
    }
}

using 선언

범위 지정 연산자(::)를 생략할 수 있다.

#include <iostream>
using namespace std;

네임스페이스의 중첩

네임스페이스 안에 또 다른 네임스페이스가 속할 수 있다.

namespace TEST
{
    int data = 100;
    namespace DEV
    {
        int data = 200;
        namespace WIN
        {
            int data = 300;
        }
    }
}

int main(){
    cout<<TEST::data<<'\n';             // 100
    cout<<TEST::DEV::data<<'\n';        // 200
    cout<<TEST::DEV::WIN::data<<'\n';   // 300
}

식별자 검색 순서

  • 전역 함수인 경우
    1. 현재 블록 범위
    2. 현재 블록 범위를 포함하고 있는 상위 블록 범위(최대 적용 범위는 함수 몸체까지)
    3. 가장 최근에 선언된 전역 변수나 함수
    4. using 선언된 네임스페이스 혹은 전역 스페이스. 단, 두 곳에 동일한 식별자가 존재할 경우 컴파일 오류 발생
  • 클래스 메소드인 경우
    1. 현재 블록 범위
    2. 현재 블록 범위를 포함하고 있는 상위 블록 범위(최대 적용 범위는 함수 몸체까지)
    3. 클래스의 멤버
    4. 부모 클래스의 멤버
    5. 가장 최근에 선언된 전역 변수나 함수
    6. 호출자 코드가 속한 네임 스페이스의 상위 네임스페이스
    7. using 선언된 네임스페이스 혹은 전역 스페이스. 단, 두 곳에 동일한 식별자가 존재할 경우 컴파일 오류 발생

가장 최근에 선언된 전역 변수

전역 변수는 네임스페이스를 생각하지 말고 선언 순서를 생각해야 한다.

using 선언과 전역 변수

using 예약어를 사용하여 같은 이름의 변수가 발생할 경우에는 컴파일 에러가 발생한다.


좋은 거

실력 있는 개발자는 미래의 유지보수 문제에 대응할 수 있도록 현재 코드를 작성할 줄 알아야 한다.

Google Styled Guide : 코딩 규칙 참고 링크


연습 문제

Q1
함수 원형에서 디폴트 값을 제시한 매개 변수 기준 오른쪽은 모두 디폴트 값을 제시해야 한다.
Q2
TestFunc(5)라고 호출하였을 경우 오버로딩의 모호성에 따라 컴파일 에러가 발생한다.
Q3
5개의 다중 정의 함수를 생성하는 것보다 하나의 함수 템플릿을 만드는 것이 코드 유지 보수와 효율성이 좋기 때문이다.
Q4
using
Q5
10

728x90

'공부 > C++' 카테고리의 다른 글

[C++] ⑥ 상속 기본  (0) 2020.10.14
[C++] ⑤ 연산자 다중 정의  (0) 2020.10.14
[C++] ④ 복사 생성자와 임시 객체  (0) 2020.10.14
[C++] ③ 클래스  (0) 2020.10.14
[C++] ① C와 C++의 차이  (0) 2020.08.31