본문 바로가기
코스웨어/16년 스마트컨트롤러

2016-09-20_조재찬_스터디일지_C++기초 2 (기초예제, inline함수, namespace)

by 알 수 없는 사용자 2016. 9. 20.
728x90
반응형

CPP 예제들


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/* 5개 정수 입력받아 합을 출력하는 프로그램
*/
#include <iostream>
 
int main()
{
    int num = 0;
    int sum = 0;
    for(int i=0; i<5; i++)
    { 
        std::cout << i + 1 << "번째 정수 입력: " ;
        std::cin >> num;
        sum = sum + num;
    }
    std::cout << "합계 :" << sum << std::endl;
    return 0;
}
cs



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* 이름과 전화번호를 문자열 형태로 입력받아 출력하는 프로그램
*/
#include <iostream>
 
int main()
{
    char name[100];
    char phoneNum[200];
 
    std::cout << "이름 : ";
    std::cin >> name;
 
    std::cout << "전화번호 : ";
    std::cin >> phoneNum;
 
    std::cout << "이름은 " << name << "이고 " <<
        "전화번호는 " << phoneNum << "이다 "<<std::endl;
    return 0;
}
 
cs



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* 숫자를 입력받아 그 숫자에 해당하는 단을 출력하는 구구단 프로그램
    (5 입력시 구구단 5단 출력)
*/
#include <iostream>
 
int main()
{
    int dan;
    std::cout << "구구단 출력할 단 입력 : ";
    std::cin >> dan;
    
    for (int i = 1; i < 10; i++)
        std::cout << dan << " X " << i << " = " << dan*<< std::endl;
 
    return 0;
}
cs



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
/* 급여 계산 프로그램
    기본 급여는 50만원, 물품 판매 가격의 12
    예) 판매금액이 100만원일 때, 50+100x0.12 = 62 (만원)
    
    판매금액 입력받아 급여를 출력 (-1이 될때까지 입력이 계속되야 함)
*/
#include <iostream>
 
int main()
{
    int pay;
    
    while(1)
    {
    std::cout << "판매 금액 입력 (만원단위, -1 입력시 종료) : ";
    std::cin >> pay;
 
    if (pay == -1)        
        break;    
 
    std::cout << "이번 달 급여: " << 50 + pay*0.12 << " 만원\n";
    }
    std::cout << "프로그램 종료" << std::endl;
        
    return 0;
}
cs



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
/* main함수에서 필요로 하는 swap 함수를 오버로딩으로 구현
*/
 
#include <iostream>
 
void swap(int *ptr1, int *ptr2)
{
    int temp = *ptr1;
    *ptr1 = *ptr2;
    *ptr2 = temp;
}
 
void swap(char *ptr1, char *ptr2)
{
    char temp = *ptr1;
    *ptr1 = *ptr2;
    *ptr2 = temp;
}
 
void swap(double *ptr1, double *ptr2)
{
    double temp = *ptr1;
    *ptr1 = *ptr2;
    *ptr2 = temp;
}
 
int main()
{
    int num1 = 20, num2 = 30;
    swap(&num1, &num2);
    std::cout << num1 << " " << num2 << std::endl;
 
    char ch1 = 'A', ch2 = 'Z';
    swap(&ch1, &ch2);
    std::cout << ch1 << " " << ch2 << std::endl;
 
    double dbl1 = 1.111, dbl2 = 5.555;
    swap(&dbl1, &dbl2);
    std::cout << dbl1 << " " << dbl2 << std::endl;
    
    return 0;
}
cs


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
/* 매개 변수의 디폴트 값 지정 형태를
함수 오버로딩의 형태로 재구현 (main함수 변경없이 동일한 실행결과가 나오도록)
*/
 
#include <iostream>
 
int BoxVolume(int length, int width, int height)
{
    return length*width*height;
}
 
int BoxVolume(int length, int width)
{
    return length*width*1;
}
 
int BoxVolume(int length)
{
    return length * 1 * 1;
}
 
 
int main()
{
    std::cout << "[3, 3, 3] : " << BoxVolume(333<< std::endl;
    std::cout << "[5, 5, D] : " << BoxVolume(55<< std::endl;
    std::cout << "[7, D, D] : " << BoxVolume(7<< std::endl;
    //    std::cout<<"[D, D, D] : "<<BoxVolume()<<std::endl;  lengh에는 default값이 지정되지 않았으므로 컴파일 에러
    return 0;
}
cs


inline 함수

매크로 함수는 함수가 인라인화 되어 성능향상이 있다는 장점이 있지만,
복잡한 함수의 정의는 어렵다는 단점이 있다. 
http://wowcat.tistory.com/3002

이를 위해 c++에서는 인라인 함수라는 것을 제공한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
 
inline int SQUARE(int x)
{
    return x*x;
}
 
int main()
{
    std::cout << SQUARE(5<< std::endl;
    std::cout << SQUARE(12<< std::endl;
    return 0;
}
cs

키워드 inline을 이용한 함수의 인라인화는 컴파일러에 의해 처리가 된다.
매크로 함수에 비해 디버깅이 용이하며, 컴파일러가 판단할 때 함수의 인라인화가 오히려 성능에 해가 된다면 inline 키워드를 무시하기도 한다.

다만 위의 inline 함수는 자료형에 의존적이게 되며 데이터 손실이 생길 수 있다.

inline int SQUARE(int x) { return x*x; }
int 형 기반으로 정의된 위의 inline 함수는 함수 호출 문장에서 데이터 손실이 발생하게 된다.

std::cout<< SQUARE(3.15);    // 0.15가 손실되어서 3 x 3의 결과인 9가 출력

함수의 오버로딩을 이용해 문제를 해결하고자 하면 이는 한번만 정의하면 되는 매크로 함수의 장점과는 멀어지므로 사용하지 않는다.
그래서 이러한 문제를 해결하기 위해서 template이라는 것을 이용해 (매크로 함수와 마찬가지로) 자료형에 의존적이지 않는 함수로 완성시킨다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>

template <typename T>
inline T SQUARE(T x)
{
	return x*x;
}

int main()
{
	std::cout << SQUARE(5.5) << std::endl;
	std::cout << SQUARE(12) << std::endl;
	return 0;
}

Output:
1
2
30.25
144


namespace (네임 스페이스)
: 이름을 붙여놓은 공간

이름 공간을 나눠 그 안에 함수를 정의하거나 변수를 선언한다면, 같은 이름으로 인해 충돌되는 문제가 발생하지 않는다.

#include <iostream>

namespace BestComImpl
{
	void SimpleFunc(void)
	{
		std::cout<<"BestCom이 정의한 함수"<<std::endl;
	}
}

namespace ProgComImpl
{
	void SimpleFunc(void)
	{
		std::cout<<"ProgCom이 정의한 함수"<<std::endl;
	}
}

int main(void)
{
	BestComImpl::SimpleFunc();
	ProgComImpl::SimpleFunc();
	return 0;
}

Output:
1
2
BestCom이 정의한 함수
ProgCom이 정의한 함수

위의 예제에서 보듯이 namespace를 나누면 매개변수 형이 동일한 함수가 있어도 충돌문제가 발생하지 않는다.

이름 공간을 지정할 때는 범위지정 연산자(scope resolution operator)인 :: 을 사용한다.


이름 공간 기반에서 함수 선언과 정의의 분리 
#include <iostream>

namespace BestComImpl
{
	void SimpleFunc(void);
}

namespace ProgComImpl
{
	void SimpleFunc(void);
}

int main(void)
{
	BestComImpl::SimpleFunc();
	ProgComImpl::SimpleFunc();
	return 0;
}

void BestComImpl::SimpleFunc(void)
{
	std::cout<<"BestCom이 정의한 함수"<<std::endl;
}	

void ProgComImpl::SimpleFunc(void)
{
	std::cout<<"ProgCom이 정의한 함수"<<std::endl;
}

Output:
1
2
BestCom이 정의한 함수
ProgCom이 정의한 함수


다음 예제에서와 같이 namespace를 둘 이상의 영역으로 나눌 수도 있으며, 동일한 namespace에 정의된 함수는 직접 호출이 가능하다

#include <iostream>

namespace BestComImpl
{
	void SimpleFunc(void);
}

namespace BestComImpl		// 3,8행과 같이 namespace를 둘 이상의 영역으로 나뉘어 선도 가능
{
	void PrettyFunc(void);
}

namespace ProgComImpl
{
	void SimpleFunc(void);
}

int main(void)
{
	BestComImpl::SimpleFunc();	
	return 0;
}


void BestComImpl::SimpleFunc(void)
{
	std::cout << "BestCom이 정의한 함수" << std::endl;
	PrettyFunc();					// 동일 이름공간
	ProgComImpl::SimpleFunc();		// 다른 이름공간
}

void BestComImpl::PrettyFunc(void)
{
	std::cout << "So Pretty!!" << std::endl;
}

void ProgComImpl::SimpleFunc(void)
{
	std::cout << "ProgCom이 정의한 함수" << std::endl;
}


Output:

1
2
3
BestCom이 정의한 함수
So Pretty!!
ProgCom이 정의한 함수



다음과 같이 namespace를 중첩시키는 것도 가능하다.


#include <iostream>

namespace Parent
{
	int num = 2;

	namespace SubOne
	{
		int num = 3;
	}

	namespace SubTwo
	{
		int num = 4;
	}
}

int main(void)
{
	std::cout << Parent::num << std::endl;
	std::cout << Parent::SubOne::num << std::endl;
	std::cout << Parent::SubTwo::num << std::endl;
	return 0;
}


Output:

1
2
3
2
3
4



/* 하나의 소스파일을 다음과 같이 3개의 파일로 분할 컴파일 하기

헤더파일  : main 함수를 제외한 나머지 두 함수의 선언 삽입

소스파일1 : main 함수를 제외한 나머지 두 함수의 정의 삽입

소스파일2 : main 함수만 삽입

*/


온라인에서 컴파일 및 실행해보기

-> https://goo.gl/eHaIhO



namespace에 대해 공부했기 때문에 std::cout은 namespace std에 선언된 cout이라는 의미임을 알 수 있다.




using을 이용한 namespace 명시


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>

namespace Hybrid
{
	void HybFunc()
	{
		std::cout << "So Simple function!" << std::endl;
		std::cout << "In namespace Hybrid!" << std::endl;
	}
}

int main()
{
	using Hybrid::HybFunc;	
	// namespace Hybrid에 정의된 HybFunc를 namespace지정없이 호출하겠단 선언
	HybFunc(); // 14행의 using선언을 통해 namespace 지정없이 HybFunc 함수 호출
	return 0;
}

Output:
1
2
So Simple function!
In namespace Hybrid!


위의 예제는 using선언이 main함수내에 존재하는데, 이러한 경우 지역변수의 성격과 동일하다.

따라서 프로그램 전체 영역에 효력을 미치게 하려면 전역변수와 같이 함수밖에 선언을 한다.


함수밖에 using선언

1
2
3
4
5
6
7
8
9
#include <iostream>
using std::cout;
using std::endl;

int main()
{
	cout << "Hello, World!" << endl;
	return 0;
}


Output:

1
Hello, World!



다음과 같이 namespace std에 선언된 모든 것에 접근할 때에 namespace 지정을 생략하도록 선언할 수도 있다.

하지만 이와 같은 선언은 이름충돌이 발생할 확률이 상대적으로 높아지기에 적절한 판단하에 쓰는 것이 중요하다.

1
2
3
4
5
6
7
8
#include <iostream>
using namespace std;

int main()
{
	cout << "Hello, World!" << endl;
	return 0;
}


Output:

1
Hello, World!




namespace 중첩시 별칭을 주기위한 선언


#include <iostream>
using namespace std;

namespace AAA
{
	namespace BBB
	{
		namespace CCC
		{
			int num1;
			int num2;
		}
	}
}

int main()
{	
	namespace ABC = AAA::BBB::CCC;		// AAA::BBB::CCC를 namespace ABC로 별칭함
	AAA::BBB::CCC::num1 = 20;	// 별칭없이 중첩된 namespace에 차례로 접근
	ABC::num2 = 30;				// 별칭을 이용해 namespace에 접근

	cout << AAA::BBB::CCC::num1 << endl;	// 별칭없이 접근
	cout << ABC::num2 << endl;				// 별칭 ABC를 통해 접근

	return 0;
}


Output:

1
2
20
30



지역변수 이름이 전역변수와 이름이 같은 경우, 전역변수는 지역변수에 의해 가려진다.

SimpleFunc 함수내에서 전역변수 val에 접근할 때에는 범위지정 연산자 :: 를 사용하면 된다. (namespace에 속하지않은 전역변수)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
using namespace std;

int val = 100;		// 전역변수 선언

int main()
{
	int val = 20;	// 지역변수
	val += 3;		// 지역변수 val의 값 3 증가
	::val += 7;		// 전역변수 val의 값 7 증가

	cout << val << endl;	// 지역변수 val의 값 출력
	cout << ::val << endl;	// 전역변수 val의 값 출력
		
	return 0;
}


Output:

1
2
23
107


728x90