C언어의 매크로 함수와 유사하다. 매크로 함수의 장점은 일반적인 함수에 비해서 실행속도에 이점이 있다는 것이지만, 정의하기 복잡하다. 이때, 일반 함수처럼 정의가 가능하며 실행속도에 이점이 있는 함수가 인라인 함수이다.
// 매크로 함수
#define SQUARE(X) ((X)*(X))
// 인라인 함수
inline int SQUARE(int x)
{
return x*x;
}
매크로 함수의 경우, 자료형에 의존적이지 않은 함수가 되어, 데이터 손실이 발생하지 않는다.
인라인 함수의 경우 자료형에 의존적이어서 데이터 손실이 발생할 수 있다. 다만, C++의 템플릿(T)을 사용하면, 이러한 단점을 보안할 수 있다.
05. Namespace
동일한 이름의 서로 다른 기능의 함수를 사용하기 위해, 즉 이름 충돌 방지를 위한 해결책
namespace NAME
{
// namespace inside
SpecialFunction()
{
.
.
.
}
namespace NAME_SUB_ONE
{
int num = 5;
}
}
.
.
.
int main(void)
{
NAME::SpecialFunction();
cout << NAME::NAME_SUB_ONE::num << std::endl;
return 0;
}
Namespace안에 Namespace를 호출하는 것 또한 가능하며, 사용법은 위 예시와 같다.
만일, 그때그때 Namespace를 선언하기 귀찮다면, using keyword를 사용할 수 있다.
Namespace에 별칭을 부여한느 것 또한 가능하다. 가령 위 함수에서 namespce nso = NAME::NAME_SUB_ONE; 와 같은 형식으로 선언하면 된다.
만일 지역변수의 이름과 전역변수의 이름이 같다면, 범위지정 연산자(::)를 통해 해결할 수 있다.
int val = 100 // global variable
int SimpleFunc(void)
{
int val = 20; // local variable
val += 3; // local variable +3
}
.
.
.
int val = 100 // global variable
int SimpleFunc(void)
{
int val = 20; // local variable
val += 3; // local variable +3
::val += 7 // global variable +7
}
int num = 2759;
int &num2 = num1;
int &num3 = num1;
int &num4 = num1;
------------------
int num = 2759
int &num2 = num1;
int &num3 = num2;
int &num4 = num3;
참조자의 선언 가능범위
참조자는 변수에 대해서만 선언이 가능하고, 선언됨과 동시에 누군가를 참조해야한다.
위와 같은 변수의 범위에는 배열 또한 포함된다.
참조자는 NULL 초기화가 불가하다.
int &ref = 20; (X)
int &ref; (X)
int &ref = NULL; (X)
.
.
.
int arr[3] = {1,3,5};
int &ref = arr[0]; (O)
08. Reference & Function
Call-by-value의 경우, 함수 외부에서 선언된 변수에 접근이 불가능하다. 그래서 보통 함수 외부에서 선언된 변수에 접근하기 위해서는 Call-by-reference 기반의 함수를 사용한다.
Simplefunc01의 경우, Call-by-value라 해야 옳다. 이는, 함수의 연산 주체가 '값(value)'이기 때문이다. 다만 그 값이 주소 값일 뿐이다.
반대로 Simpefucn02의 경우, 주소 값을 이용, 함수 외부에 선언된 변수를 '참조(reference)'하였으므로, Call-by-reference이다. 즉, Call-by-reference는 "주소 값을 전달 받아, 함수 외부에 선언된 변수에 접근하는 형태의 함수호출'을 말한다. 쉽게 말하자면, 주소 값이 외부 변수의 참조도구로 사용되는 함수의 호출이 Call-by-reference이다.
이러한 참조는 참조자를 이용해서도 가능하다.
void SwapByRef(int &ref1, int &ref2)
{
int temp = ref1;
ref1 = ref2;
ref2 = temp;
// Call-by-reference
}
이 과정에서, 앞선 참조자의 규칙인 '선언과 동시에 초기화 되어야 한다.'가 충족되지 않았다고 생각할 수 있다. 하지만, parameter의 경우, 함수가 호출되어야 초기화가 진행되기 때문에 함수 호출 시 초기화 값이 전해지면서 문제가 생기지 않는다.
다만 이러한 활용이 오히려 단점이 될 수 있다. 다음 코드를 보자.
int num = 24;
HappyFunc(num);
cout << num << endl;
C언어의 경우 위의 코드는 당연하게도 24가 출력된다. 하지만, C++의 경우 다음과 같은 이유로 출력을 단정지을 수 없다.
즉, 처음에 num1을 선언한 뒤, 선언한 num1을 RefRetFuncOne함수의 int &ref선언을 통해 num에는 ref라는 별칭이 생겼다. 이 선언 과정을 진행한 뒤, 함수 내에서 ref의 값을 1 추가하고, num1의 값을 1 추가한다. 이렇게 ref의 값이 2가 되었을 때, 2가 된 값을 num2가 가진다. 그 뒤, num1에 1을 추가하고, num2에 100을 더한다. 그렇게 나온 값이 num1 : 3, num2: 102이다.
int& RetuRefFunc(int n)
{
int num = 20;
num += n;
return num;
}
만일, int &ref = RetuRefFunc(10); 의 형태로 위 함수를 호출하면, 다음과 같이 작동할 것이다.
ref라는 참조자가 num을 참조한다.
참조된 num이라는 지역변수는 함수의 코드를 수행한 뒤 반환된다.
이때, 지역변수 num은 소멸된다.
따라서 지역 변수를 참조형으로 반환하는 일은 권장되지 않는다.
09. Dynamic Allocation
C
C++
allocate
malloc
new
delete
free
delete
header
stdlib.h
-
C언어의 경우, 할당할 대상의 정보를 반드시 바이트 크기단위로 전달해야 한다. 또한 반환형이 void형 포인터이기 때문에 적절한 형 변환을 거쳐야 할 필요가 있다.
하지만, C++에서 제공하는 new와 delete의 경우 이러한 불편함을 제거한다.
C
C++
allocate
int * ptr = (int*)malloc(sizeof(int)*4)
int * ptr = new int;
delete
free(ptr)
delete ptr
객체의 생성에 malloc와 free는 권장되지 않는다. 이는, new와 malloc 함수의 동작방식의 차이가 있기 때문인데, new의 경우 C++에 의해 기본적으로 제공되지만, malloc의 경우 별도의 라이브러리가 요구된다. 또한 new의 경우, 생성자를 자동호출해준다.
C++의 경우, new 연산자를 이용해서 할당된 메모리 공간도 변수로 간주한다. 즉, 참조자의 선언이 가능하도록 하고 있다. 이러한 특징은참조자의 선언을 통해 포인터 연산 없이 힙 영역에 접근이 가능하다는 점을 알려준다.
int *ptr = new int;
int &ref = *ptr;
ref = 20;
cout << *ptr << endl;