[Chap 01] C언어 기반의 C++
C언어 기반의 C++
💎 printf와 scanf를 대신하는 입출력 방식
🔆 printf == std::cout« 출력 변수나 문자
#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;
}
>>>
Hello World!
Hello World!
20 A 3.14
- printf == std::cout« 출력 변수나 문자
- \n == std::endl;
🔆 scanf == std::cin»입력 받을 변수이름
#include <iostream>
int main()
{
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;
}
>>>
첫 번째 숫자 입력: 10
두 번째 숫자 입력: 20
덧셈 결과: 30
- scanf == std::cin»입력 받을 변수이름
🔆 한 번에 2개 이상 문자 입력받기
#include <iostream>
int main()
{
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;
}
>>>
두 개의 숫자입력: 3 7
두 수 사이의 정수 합: 11
🔆 문자열 입력 받기
#include <iostream>
int main()
{
char name[100];
char lang[200];
std::cout << "이름은 무엇입니까? ";
std::cin >> name;
std::cout << "좋아하는 프로그래밍 언어는 무엇인가요? ";
std::cin >> lang;
std::cout << "내 이름은 " << name << "입니다" << std::endl;
std::cout << "제일 좋아하는 언어는 " << lang << "입니다." << std::endl;
return 0;
}
>>>
내 이름은 손수경입니다
제일 좋아하는 언어는 글쎼,,,입니다.
💎 함수 오버로딩
#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()
{
MyFunc();
MyFunc('A');
MyFunc(12, 13);
return 0;
}
>>>
MyFunc(void) called
MyFunc(char c) called
MyFunc(int a, int b) called
💎 매개변수의 디폴트 값
#include <iostream>
int Adder(int num1 = 1, int num2 = 2)
{
return num1 + num2;
}
int main()
{
std::cout << Adder() << std::endl;
std::cout << Adder(5) << std::endl;
std::cout << Adder(3, 5) << std::endl;
return 0;
}
>>>
3
7
8
- 매개변수로 전달된 값이 없으니 디폴트 값인 1과 2가 더해져 3이 출력
- num1에 해당하는 인자만 전달이 되었으니 num2는 디폴트 값인 2로 간주되어 5 + 2로 7이 출력
- num1과 num2의 값이 모두 전달되었으므로 3 + 5로 8이 출력
🔆 디폴트 값은 함수 선언부에만 정의하면 됨
#include <iostream>
int Adder(int num1 = 1, int num2 = 2);
int main()
{
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;
}
>>>
3
7
8
이것처럼 디폴트 값은 함수의 선언부에 정의를 하여 main 함수에서도 디폴트 값을 사용할 수 있도록 해야 된다.
즉, main 함수 위에 함수 정의를 하던지, 아니면 선언을 통해서 디폴트 값을 지정할 수 있다.
🔆 부분적 디폴트 값 설정
부분적으로 디폴트 값을 설정할 수 있는데, 이때 디폴트 값은 반드시 오른쪽 매개변수의 디폴트 값부터 채우는 형태로 정의해야 된다.
예를 들어
int YourFunc(int num1 = 3, int num2 = 5, int num3); //X
int YourFunc(int num1, int num2 = 3, int num3 = 5); //O
아래 예시는 반드시 하나 이상의 인자가 전달이 되어야 한다. length가 디폴트 값을 가지고 있지 않기 때문!
#include <iostream>
int BoxVolume(int length, int width = 1, int height = 1);
int main()
{
std::cout << "[3, 3, 3] : " << BoxVolume(3, 3, 3) << std::endl;
std::cout << "[5, 5, D] : " << BoxVolume(5, 5) << std::endl;
std::cout << "[7, D, D] : " << BoxVolume(7) << std::endl;
return 0;
}
int BoxVolume(int length, int width, int height)
{
return length * width * height;
}
>>>
[3, 3, 3] : 27
[5, 5, D] : 25
[7, D, D] : 7
- length: 3 / width: 3 / height: 3
- length: 5 / width: 5 / height: 1
- length: 7 / width: 1 / height: 1
💎 인라인 함수
함수가 인라인화 되었다 = C언어에서의 메크로 함수
메크로 함수는 함수의 기능을 정의하여 이름만 작성하여서 알아서 구현부를 통해 값이 정의가 된다. 이를 함수의 인라인화 되었다 라고 표현을 한다.
#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;
}
>>>
25
144
inline 키워드를 사용해서 인라인 함수를 정의한다.
C언어에서 매크로 함수의 경우는 전처리기에 의해서 처리되지만 키워드 inline을 이용한 함수의 인라인화는 컴파일러에 의해 처리가 된다.
따라서 컴파일러는 똑똑하기 때문에 함수의 인라인화가 오히러 성능에 해가 된다고 판단할 경우, inline 키워드를 무시한다. 또한 컴파일러는 필요한 경우 ㅇ리부 함수를 임의로 인라인 처리를 하기도 한다.
하지만 매크로 함수의 경우 매개변수의 데이터형에 제약이 없었다. 위의 inline 키워드의 경우는 데이터형의 제약이 생길 수 밖에 없다. 이는 C++에 템플릿이라는 것을 이용하면 매크로 함수와 마찬가지로 데이터형에 의존적이지 않은 함수를 완성할 수 있다.
💎 이름 공간(namespace)에 대한 소개
namespace는 이름을 붙여놓는 공간을 위미한다.
#include <iostream>
namespace BestComImp1
{
void SimpleFunc(void)
{
std::cout << "BestCom이 정의한 함수" << std::endl;
}
}
namespace ProgComImp1
{
void SimpleFunc()
{
std::cout << "ProgCom이 정의한 함수" << std::endl;
}
}
int main()
{
BestComImp1::SimpleFunc();
ProgComImp1::SimpleFunc();
}
>>>
BestCom이 정의한 함수
ProgCom이 정의한 함수
::연산자를 범위 지정 연산자라고 한다. 이처럼 namespace는 같은 이름의 함수를 다른 이름 공간에서 정의했다면 해당 이름 공간의 함수를 출력해주는 것을 확인할 수 있다.
🔆 이름 공간 기반의 함수 선언과 정의의 구분
#include <iostream>
namespace BestComImp1
{
void SimpleFunc();
}
namespace BestComImp1
{
void PrettyFunc();
}
namespace ProgComImp1
{
void SimpleFunc();
}
int main()
{
BestComImp1::SimpleFunc();
ProgComImp1::SimpleFunc();
return 0;
}
void BestComImp1::SimpleFunc()
{
std::cout << "BestComImp1's Function" << std::endl;
PrettyFunc(); //동일 이름 공간
ProgComImp1::SimpleFunc(); //다른 이름 공간
}
void BestComImp1::PrettyFunc()
{
std::cout << "So Pretty" << std::endl;
}
void ProgComImp1::SimpleFunc()
{
std::cout << "ProgComImp1's Function" << std::endl;
}
>>>
BestComImp1's Function
So Pretty
ProgComImp1's Function
ProgComImp1's Function
코드를 살펴보자면
- 이름공간 기반의 함수를 선언 후 정의할 때는 어느 부분의 이름 공간에 해당하는 함수인지를 정의한다.
- 같은 공간의 함수인 경우는 이름 공간을 붙히지 않고 함수를 사용할 수 있다.
- 다른 공간의 함수인 경우는 이름 공간을 붙혀서 함수를 사용할 수 있다.
🔆 이름 공간의 중첩
이름공간은 다른 이름공간 안에 삽입될 수 있다.
#include <iostream>
namespace Parent
{
int num = 2;
namespace SubOne
{
int num = 3;
}
namespace SubTwo
{
int num = 4;
}
}
int main()
{
std::cout << Parent::num << std::endl;
std::cout << Parent::SubOne::num << std::endl;
std::cout << Parent::SubTwo::num << std::endl;
}
>>>
2
3
4
출력 형식을 보면 std::cout와 std::cin, std::endl과 유사한 것을 확인할 수 있다. 위 코드를 보자면 Parent 공간 안에 SubOne, SubTwo가 있고 각각 같은 이름의 변수를 다르게 정의하고 있다. 이를 :: 연산자를 통해서 구분하여서 출력하는 것을 알 수 있다.
같은 의미로 std::cout는 std 이름 공간안에 정의되어 있는 cout라는 것을 알 수 있다. 하지만 매변 출력할 때마다 std::후에 cout, cin, endl를 붙히는 것은 귀찮다.
💡sol. using을 이용한 이름공간의 명시
#include <iostream>
namespace Hybrid
{
void HybFunc()
{
std::cout << "So simple function!" << std::endl;
std::cout << "In namespace Hybrid!" << std::endl;
}
}
namespace Hybrid
{
void TempFunc()
{
std::cout << "Another Hybrid's Function" << std::endl;
}
}
int main()
{
using Hybrid::HybFunc;
HybFunc();
Hybrid::TempFunc();
return 0;
}
>>>
So simple function!
In namespace Hybrid!
Another Hybrid's Function
using을 사용해서 Hybrid::HybFunc 를 그냥 HybFunc()으로 사용할 수 있도록 하였다. 하지만 같은 공간에 있는 다른 함수는 마찬가지로 이름공간까지 같이 붙혀주어야 한다.
왜냐면 Hybrid::HybFunc만 using 키워드를 붙혔기 때문이다. 하지만 모든 Hybrid 이름 공간을 가지고 있는 함수들을 간단하게 사용하기 위해서는 다음과 같이 해주면 된다.
#include <iostream>
namespace Hybrid
{
void HybFunc()
{
std::cout << "So simple function!" << std::endl;
std::cout << "In namespace Hybrid!" << std::endl;
}
}
namespace Hybrid
{
void TempFunc()
{
std::cout << "Another Hybrid's Function" << std::endl;
}
}
int main()
{
using namespace Hybrid; //🌟
HybFunc();
TempFunc();
return 0;
}
같은 의미로 std::cout, std::cin, std::endl 모두 다음과 같이 사용할 수 있다.
#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;
}
>>>
Hello World!
Hello World!
20 A 3.14
근데 뭐,,,,,,,,,,std::를 꼭 붙혀서 사용하는 것이 좋은 습관이라고 한다,,,그렇다고 한다……….
🔆 이름공간의 별칭 지정
#include <iostream>
using namespace std;
namespace AAA
{
namespace BBB
{
namespace CCC
{
int num1;
int num2;
}
}
}
int main()
{
AAA::BBB::CCC::num1 = 20;
AAA::BBB::CCC::num2 = 30;
namespace ABC = AAA::BBB::CCC;
cout << ABC::num1 << endl;
cout << ABC::num2 << endl;
}
>>>
20
30
💎 범위지정 연산자의 또 다른 기능
지금까지 봤던 범위지정자 연산자 :: 는 어떤 이름 공간에 속해져 있는지 범위를 지정해주는 역할을 하였다. 하지만 :: 는 지역 변수 범위에서 전역변수로 접근이 가능한 역할을 하기도 한다.
예를 들어서
#include <iostream>
int val = 10;
void add()
{
int val = 20;
val += 10; // 지역 변수 20에서 10 증가
::val += 5; // 전역 변수 10에서 5 증가
}
int main()
{
add();
std::cout << "val: " << val << std::endl;
}
>>>
val: 15
처럼 전역 변수의 값을 바꾸기 위해서 사용되기도 한다.
댓글남기기