C++, based on C

노정훈·2023년 7월 20일
0

C++

목록 보기
1/1

I/O System

printf를 대신하는 데이터의 출력

// In[1]
#include <iostream>
int main(void) {
	int num = 20;
	std::cout << "Hello World!" << std::endl;
	std::cout << "Hello" << "World" << std::endl;
	std::cout << num << ' ' << 'A';
	std::cout << ' ' << 3.14 << std::endl;
	return 0;
}
// Out[1]
Hello World!
Hello World!
20 A 3.14
  • 입출력에 관련된 일을 하기 위해 #include <iostream> 헤더파일 선언
  • 출력을 하기 위해서는 std::cout<<'출력대상'; 형태를 사용
  • 출력대상 에는 int, float, string 등이 올 수 있음.
  • C언어에서 출력포맷을 지정하는 것과 달리 데이터의 성격에 따라 출력이 이루어짐.
  • << 연산자를 이용하면 std::cout<<'출력대상1'<<'출력대상2'; 형태로 연이어 출력이 가능
  • << 연산자를 이용한 std::endl의 출력은 개행으로 이어짐.

scanf를 대신하는 데이터의 입력

// In[2]
#include <iostream>
int main(void) {

	int val1;
	std::cout << "첫 번째 숫자입력: ";
	std::cin >> val1;

	int val2;
	std::cout << "두 번째 숫자입력: ";
	std::cin >> val2;

	int result = val1 + val2;
	std::cout << "덧셈결과: " << result << std::endl;
	return 0;
}
// Out[2]
첫 번째 숫자입력: 3
두 번째 숫자입력: 5
덧셈결과: 8
  • 데이터의 입력을 받기 위해서는 std::cin>>'변수' 형태를 사용
// In[3]
#include <iostream>
int main(void) {

	int val1, val2;
	int result = 0;
	std::cout << "두 개의 숫자입력: ";
	std::cin >> val1 >> val2;

	if (val1 < val2) {
		for (int i = val1 + 1; i < val2; i++)
			result += i;
	}
	else {
		for (int i = val2 + 1; i < val1; i++)
			result += i;
	}
	std::cout << "두 수 사이의 정수 합: " << result << std::endl;

	return 0;
}
// Out[3]
두 개의 숫자입력: 3 7
두 수 사이의 정수 합: 15
  • 위와 같이 std::cin>>'변수 1'>>'변수 2'; 의 구조로 연속적인 데이터 입력이 가능
  • 첫 번째 데이터와 두 번재 데이터 간의 경계는 TAB , SPACE BAR, ENTER 의 입력과 같은 공백에 의해 나누어짐.

배열 기반 문자열 입출력

// In[4]
#include <iostream>
int main(void) {

	char name[100];
	char lang[100];

	std::cout << "이름은 무엇입니까? ";
	std::cin >> name;

	std::cout << "좋아하는 프로그래밍 언어는? ";
	std::cin >> lang;

	std::cout << "내 이름은 " << name << "입니다.\n";
	std::cout << "좋아하는 언어는 " << lang << "입니다." << std::endl;

	return 0;
}
// Out[4]
이름은 무엇입니까? Kim
좋아하는 프로그래밍 언어는? C++
내 이름은 Kim입니다.
좋아하는 언어는 C++입니다.
  • 위의 코드는 앞서 소개한 것과 별반 다르지 않음. 입출력의 대상이 문자열이라는 것이 차이점.
  • \n 과 같은 특수문자는 C언어에서와 같은 의미를 지님.

Function Overloading

  • C++에서는 함수호출 시 전달되는 인자를 통해 호출하고자 하는 함수의 구분이 가능하기 때문에 매개변수의 형태가 다르다면 동일한 이름의 함수정의를 허용함.
  • 이를 Function Overloading(함수 오버로딩) 이라고 함.
  • C언어에서 function overloading을 허용하지 않는 이유는 C언어는 함수의 이름만 이용하여 호출대상을 찾기 때문이고, C++은 함수의 이름과 매개변수의 선언을 보고 호출대상을 찾기 때문에 function overloading이 가능한 것.
  • 위와 같은 내용에 따라, function overloading이 가능하기 위해서는 매개변수의 자료형 또는 개수가 달라야만 한다.
// In[5]
#include <iostream>

void Myfunc(void) {
	std::cout << "Myfunc(void) called" << std::endl;
}

void Myfunc(char c) {
	std::cout << "Myfunc(char c) called" << std::endl;
}

void Myfunc(int a, int b) {
	std::cout << "Myfunc(int a,int b) called" << std::endl;
}

int main(void) {
	Myfunc();
	Myfunc('A');
	Myfunc(12, 13);
	return 0;
}
// Out[5]
Myfunc(void) called
Myfunc(char c) called
Myfunc(int a,int b) called

Default Value

// In[6]
#include <iostream>

int adder(int num1 = 1, int num2 = 2) {
	return num1 + num2;
}

int main(void) {
	std::cout << adder() << std::endl;
	std::cout << adder(5) << std::endl;
	std::cout << adder(3, 5) << std::endl;
	return 0;
}
// Out[6]
3
7
8
  • 위의 코드를 함수 원형을 별도로 선언하는 경우로 바꾸어줄 경우 매개변수의 default 값은 함수의 원형 선언에만 위치시켜야 함.
// In[7]
#include <iostream>

int adder(int num1 = 1, int num2 = 2);

int main(void) {
	std::cout << adder() << std::endl;
	std::cout << adder(5) << std::endl;
	std::cout << adder(3, 5) << std::endl;
	return 0;
}

int adder(int num1, int num2) {
	return num1 + num2;
}
// Out[7]
3
7
8

부분적 default 값 설정

  • 위에서 본 예제처럼 default 값을 전부 지정할 수도 있지만 일부분만 지정할 수도 있음.
  • 단, 오른쪽 매개변수의 default 값을 비우는 형태로는 지정할 수 없음.
    즉, 반드시 오른쪽 매개변수의 default 값부터 채우는 형태로 정의해야 함.
  • 그 이유는 함수에 전달되는 인자가 왼쪽에서부터 오른쪽으로 채워지기 때문.
// In[8]
#include <iostream>

int box_volume(int length, int width = 1, int height = 1);

int main(void) {
	std::cout << "[3,3,3] : " << box_volume(3, 3, 3) << std::endl;
	std::cout << "[5,5,D] : " << box_volume(5, 5) << std::endl;
	std::cout << "[7,7,D] : " << box_volume(7) << std::endl;
//  std::cout << "[D,D,D] : " << box_volume() << std::endl;
	return 0;
}

int box_volume(int length, int width, int height) {
	return length * width * height;
}
// Out[8]
[3,3,3] : 27
[5,5,D] : 25
[7,7,D] : 7

Inline Function

  • 매크로 함수(# define 형태)는 일반적인 함수에 비해 실행속도에 이점이 있지만 정의하기 어렵고 복잡한 함수를 매크로의 형태로 정의하는데 한계가 있다는 단점 보유
  • 이를 해결한 것이 C++의 inline 함수
// In[9]
#include <iostream>

inline int square(int x) {
	return x * x;
}

int main(void) {
	std::cout << square(5) << std::endl;
	std::cout << square(12) << std::endl;
	return 0;
}
// Out[9]
25
144
  • 단, inline 함수를 이용하는 경우 매크로 함수와는 다르게 자료형을 정의했기 때문에 정의된 자료형과 다른 자료형이 들어오면 잘못된 값이 출력됨.
  • 매크로 함수는 자료형에 의존적이지 않게 함수를 정의할 수 있음
  • 이와 관련된 해결책으로 C++의 template이라는 것을 사용하는데 이는 뒤에 가서 알아보는걸로

About Namespace

Namespace 기본개념

  • 쉽게 말해, 특정 영역에 이름을 붙여주기 위한 문법적 요소
// In[10]
#include <iostream>

namespace bestcomimp1 {
	void simplefunc(void) {
		std::cout << "bestcom이 정의한 함수" << std::endl;
	}
}

namespace progcomimp1 {
	void simplefunc(void) {
		std::cout << "progcom이 정의한 함수" << std::endl;
	}
}

int main(void) {
	bestcomimp1::simplefunc();
	progcomimp1::simplefunc();
	return 0;
}
// Out[10]
bestcom이 정의한 함수
progcom이 정의한 함수
  • 위 코드에서 사용된 :: 연산자를 '범위 지정 연산자(scope resolution operator)'라고 하며 namespace를 지정할 때 사용하는 연산자.
  • 위의 코드를 함수의 선언과 정의를 분리하여 작성하면 다음과 같이 작성할 수 있음.
#include <iostream>

namespace bestcomimp1 {
	void simplefunc(void);
}

namespace progcomimp1 {
	void simplefunc(void);
}

int main(void) {
	bestcomimp1::simplefunc();
	progcomimp1::simplefunc();
	return 0;
}

void bestcomimp1::simplefunc(void) {
	std::cout << "bestcom이 정의한 함수" << std::endl;
}

void progcomimp1::simplefunc(void) {
	std::cout << "progcom이 정의한 함수" << std::endl;
}
  • 동일한 namespace에 정의된 함수를 호출할 때에는 namespace를 명시할 필요가 없음.

Namespace 중첩

  • namespace는 다른 namespace 안에 삽입될 수 있음
namespace Parent{
	int num=2;
    
    namespace SubOne{
    	int num=3;
    }
    
    namespace SubTwo{
    	int num=4;
    }
}
  • 위와 같은 코드에서 각각의 num에 접근하기 위해서는 다음의 문장을 실행.
std::cout << Parent::num << std::endl;
std::cout << Parent::SubOne::num << std::endl;
std::cout << Parent::SubTwo::num << std::endl;

using을 이용한 namespace 명시

// In[11]
#include <iostream>

namespace Hybrid {
	void Hybfunc(void) {
		std::cout << "So simple funtion!" << std::endl;
		std::cout << "In namespace Hybrid!" << std::endl;
	}
}

int main(void) {
	using Hybrid::Hybfunc;
	Hybfunc();
	return 0;
}
// Out[11]
So simple funtion!
In namespace Hybrid!
  • 위의 using Hybrid::Hybfunc;Hybrid 라는 namespace에서 Hybfunc을 찾으라는 일종의 선언
  • 프로그램 전체영역에 효력을 미치게 하기 위해서는 전역변수와 마찬가지로 함수 밖에 선언해줘야 함.
// In[12]
#include <iostream>
using namespace std;

int main(void) {
	int num = 20;
	cout << "Hello World!" << endl;
	cout << "Hello " << "World!" << endl;
	cout << num << ' ' << 'A';
	cout << ' ' << 3.14 <<endl;
	return 0;
}
// Out[12]
Hello World!
Hello World!
20 A 3.14
  • 위와 같은 선언을 통해 namespace std 에 선언된 모든 것에 대해 namespace 지정 생략을 명령할 수 있음.
  • 다만 이렇게 선언할 경우 충돌이 발생할 확률은 상대적으로 높아짐.

Namespace 별칭 지정

#include <iostream>
using namespace std;

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

int main(void) {
	AAA::BBB::CCC::num1 = 20;
	AAA::BBB::CCC::num2 = 30;

	namespace ABC = AAA::BBB::CCC;
	cout << ABC::num1 << endl;
	cout << ABC::num2 << endl;
	return 0;
}
  • 위와 같이 namespace가 중첩되어 변수에 접근하기 번거로울 때 간단히 정리할 수 있음.

Scope Resolution Operator의 다른 기능

  • 지역변수의 이름이 전역변수의 이름과 같은 경우 전역변수는 지역변수에 의해 가려짐.
#include <iostream>
using namespace std;

int val = 100; //전역변수 

int simplefunc(void) {
	int val = 20; //지역변수
	val += 3; //지역변수 val 값 +3
	::val += 7; //전역변수 val 값 +7
}
  • 위와 같은 예제의 simplefunc 함수 내에서 전역변수에 접근하기 위해서는 scope resolution operator를 사용하면 됨.
profile
노정훈

0개의 댓글