chapter 01. C언어 기반의 C++
윤성우의 열혈 C++ 프로그래밍
1. 변경된 입출력 방법
1) 표준 입출력을 위한 헤더파일(stdio.h > iostream)
#include <stdio.h> // 예전 C
#include <iostream> // 바뀐 C++
2) 출력(std::cout <<)
printf("Hello world"); // 예전 C
std::cout<<"Hello World"; // 바뀐 C++
std::cout<<"Hello "<<"World"; // 출력할 데이터는 "<<" 이후 연속으로 출력 가능함
3) 입력(std::cin >>)
int val1;
int val2;
scanf("%d", &val1); // 예전 C
std::cin>>val1; // 바뀐 C++
std::cin>>val1>>val2; // 입력할 데이터는 ">>" 이후 연속으로 입력 가능함
2. 오버로딩
> 동일한 이름의 함수가 정의되는 경우
1) 전개 및 예제
C에서는 함수 오버로딩이 불가능(최신 C에서는 가능)한 반면
C++에서는 함수 오버로딩이 가능
이유는 C에서는 함수 이름으로만 함수를 찾는데, C++에서는 함수 이름과 매개변수를 기준으로 찾기 때문
#include <iostream>
void MyFunc(void) // 인수 없음
{
std::cout<<"MyFunc(void) called"<<std::endl;
}
void MyFunc(char c) // 인수 1개
{
std::cout<<"MyFunc(char c) called"<<std::endl;
}
void MyFunc(int a, int b) // 인수 2개
{
std::cout<<"MyFunc(int a, int b) called"<<std::endl;
}
int main(void)
{
MyFunc();
MyFunc('A');
MyFunc(12, 13);
return 0;
}
3. 매개변수의 디폴트 값(Default Value)
> 매개변수 선언시 기본적으로 설정되어 있는 값
#include <iostream>
int Adder(int num1=1, int num2=2)
{
return num1+num2;
}
int main(void)
{
std::cout<<Adder()<<std::endl; // int num1 = 1, int num2 = 2
std::cout<<Adder(5)<<std::endl; // int num1 = 5, int num2 = 2
std::cout<<Adder(3, 5)<<std::endl; // int num1 = 3, int num2 = 5
return 0;
}
함수의 매개변수에 인자를 전달시 왼쪽부터 오른쪽으로 채워지기 때문에
함수의 매개변수 수보다 적은 인수를 전달하면 왼쪽부터 매개변수의 값이 저장되고, 바뀌지 않은 값은 디폴트 값으로 저장된다.
4. 인라인(inline) 함수
1) 매크로 함수의 특징
#include<iostream>
#define SQUARE(X) ((X)*(X)) // 매크로 함수 정의
int main(void){
std::cout<< SQUARE(3) << std::endl; // 매크로 함수 사용
return 0;
}
매크로 함수는 위와 같이 정의하고, 사용함
전처리 단계에서 단순한 텍스트 치환 방식을 사용하여 코드를 삽입하는 방식임
이는 잠재적으로 프로그램의 안정성을 떨어트릴 수 있는 단점이 있다
2) 인라인 함수의 사용
#include<iostream>
inline int SQUARE(int x){ // 인라인 함수 정의
return x * x;
}
int main(void){
std::cout<<SQUARE(3)<<std::endl; // 인라인 함수 사용
std::cout<<SQUARE(8)<<std::endl;
return 0;
}
인라인 함수는 위와 같이 정의하고, 사용함
컴파일러 단계에서 다른 함수들과 같이 처리되어 코드를 삽입하는 방식임
매크로와 사용은 비슷하지만 안정성을 확보할 수 있는 장점이 있다
5. 이름공간(namespace)
> 함수의 이름이 같을 때 이름공간을 사용하여 구분 가능
1) 이름공간 사용
#include <iostream>
namespace BestComImpl{ // namespace(자료형과 비슷하게 먼저 선언) / "사용할 이름"
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;
}
SimpleFunc 라는 같은 이름의 함수도 namespace로 구분하면 각각 다른 함수처럼 사용할 수 있음
chapter 02. C언어 기반의 C++ 2
1. 참조자(Reference)
1) 사용법
#include<iostream>
using namespace std;
int main(void){
int num1 = 100;
int &num2 = num1; // num1 변수를 num2가 참조
int num3 = num2 + 20;
cout<<"num3 = "<<num3<<endl;
return 0;
}
>
num3 = 130
#include<iostream>
using namespace std;
int main(void){
int num1 = 100;
int *pnum = &num1; // num1의 주소를 pnum에 저장
int num3 = *pnum + 20; // pnum이 가리키는 주소의 값을 읽어와 20을 더함
cout<<"num3 = "<<num3<<endl;
return 0;
}
>
num3 = 130
포인터 역참조와 유사한데
포인터 역참조는 가르키고 있는 변수의 주소의 값을 사용하는 것이고
참조자는 변수를 다르게 부르는 것 뿐이라 주소와 관계가 없어
엄연히 다르다고 볼 수 있다
2) 주의사항
- 선언과 동시에 변수를 참조하도록 해야함
- 변수에 대해서만 선언 가능(상수 불가능, 예외 존재)
- 미리 참조자를 홀로 선언 후 누군가를 참조하는 것은 불가능
- 참조자 선언시 NULL 초기화 불가능
3) 함수와 관계
void func(int &num1, int &num2)
위와 같은 매개변수의 인자를 참조자로 받는 경우
주의사항 중 선언과 동시에 변수를 참조하도록 해야함과 배치될 수 있어보임
하지만 이는 함수 호출시 전달 인자로 변수로 참조하는 선언으로 해석해 가능한 사용범위라고 할 수 있음
4) const 참조자
void func(const int &ref)
위와 같이 const 참조자를 인자로 받는 경우에는
인자로 받은 값을 변경하지 않을 것이라는 명시적 약속을 함으로써 코드의 안정성이 높아짐
5) 반환형이 참조자인 경우
#include <iostream>
using namespace std;
int & RefRetFuncOne(int &ref)
{
ref++;
return ref;
}
int main(void)
{
int num1=1; // num1 변수 선언
int &num2=RefRetFuncOne(num1);
// 함수의 &ref는 num1의 별칭이 됨
// ref의 값을 1 추가하여 num1 에 들어가 있는 값을 1 더하고, 참조로 반환해 num2라는 새로운 참조자가 받음
// num2는 num1의 새로운 별칭이 됨
num1++;
num2++;
// num1을 1 추가하여 num1의 값을 1 더함
// num2를 1 추가하여 num2가 참조하고 있는 num1의 값을 1 더함
cout<<"num1: "<<num1<<endl;
cout<<"num2: "<<num2<<endl;
return 0;
}
2. new / delete
> 메모리 동적할당의 C++ 버전
기존 malloc의 경우는 void*형 함수였기 때문에 변수에 저장시 형 변환을 거쳐야 하는 번거로움이 존재
하지만 new의 경우에는 자료형만 명시해주면 되기에 간결함
#include <iostream>
#include <string.h>
#include <stdlib.h>
using namespace std;
char * MakeStrAdr(int len)
{
char * str=(char*)malloc(sizeof(char)*len); // 문자열 저장을 위한 배열을 동적할당
return str;
}
int main(void)
{
char * str=MakeStrAdr(20);
strcpy(str, "I am so happy~");
cout<<str<<endl;
free(str); // 메모리 공간 소멸
return 0;
}
기존 C에서 사용했던 malloc, free
#include <iostream>
#include <string.h>
using namespace std;
char * MakeStrAdr(int len)
{
char * str=new char[len];
return str;
}
int main(void)
{
char * str=MakeStrAdr(20);
strcpy(str, "I am so happy~");
cout<<str<<endl;
// free(str);
delete []str;
return 0;
}
C++에서 사용하는 new, delete
C++ study1

>
과제에 앞서
분할 컴파일 시에는 크게
main.cpp
func.h(예를 든 것)
func.cpp(예를 든 것)
필요
func.h 같은 헤더 파일은 함수를 선언 및 구조체, 전역변수(extern) 저장
func.cpp는 func.h를 include 하고 함수를 정의
main.cpp에서는 func.h를 include 하여 함수를 호출
1. 헤더파일 필요성 / 헤더파일 중복 문제 이에 따른 해결법
1)
앞서 헤더파일은 함수 선언 및 구조체, 전역변수(extern) 저장하는 용도로 사용하는데
여기서 구조체나 전역변수의 경우에는 main.c에서 include 하여 사용하기만 해도 저장된 구조체 등을 사용할 수 있다는 장점이 있어 필요성이 있다.(함수는 별도의 .cpp와 함께 컴파일하는 과정 필요)
2)
그런데 문제는 first.h 라는 헤더파일의 저장된 구조체나 변수를 second.h 라는 헤더파일에서 include 하여 사용한 상태에서 발생한다
main.cpp 에서는 first.h, second.h 둘 다 include를 해야 두 구조체나 전역변수를 다 사용할 수 있는데,
이미 second.h에서 한번 include된 first.h는 main.c 입장에서는 2번 include 되는 것과 마찬가지인 것임
따라서 first.h에 조건을 사용해 중복으로 헤더파일을 include 할 수 없도록 제한을 하는 것
#ifndef _FIRST_H_ // _FIRST_H_ 매크로명이 정의되어 있지 않으면
#define _FIRST_H_ // _FIRST_H_ 매크로명 정의
~
#endif _FIRST_H_
이를 main에서 사용하면 first.h를 처음 include 할 때에는 _FIRST_H_ 가 정의되어 있지 않으므로 _FIRST_H_가 정의가 되면서 "~" 중간 부분이 사용됨
이후에 second.h에 있는 first.h가 다시 include 되면 _FIRST_H 가 정의되어 있는 상태이므로 "~" 중간 부분이 사용되지 않음
2. 둘 이상의 파일을 하나의 실행파일로 빌드하는 과정
main.cpp, func.cpp이 같은 폴더에 있다고 가정했을 때
1) 빌드
gcc main.cpp func.cpp -o main
또는
g++ main.cpp func.cpp -o main
로 main 이라는 실행파일 생성
2) 실행
./main
으로 실행파일을 실행
3. 빌드에서 전처리기(Preprocessor)와 링커(Linker)가 하는 일
1) 전처리기
- #include 처리(헤더 파일을 복사, 붙여넣기 함)
- #define 처리(정의된 매크로 이름을 매크로 값으로 텍스트 치환)
- 조건부 컴파일(이전에 중복문제를 해결할 수 있었던 방법, ifdef, endif 등)
2) 링커
> 컴파일의 마지막 단계를 담당
- 외부 참조
(main.cpp에서 헤더파일의 존재로 func.cpp의 함수를 알고 있을 때, main.cpp의 함수 호출로 func.cpp의 함수 정의와 실제 연결함)
- 라이브러리 연결
(iostream, string, stdio.h 등의 표준 라이브러리 또는 커스텀 라이브러리를 프로그램에 포함시킴)
- 실행파일 생성
(최종적으로 실행파일을 생성함)
- gcc -c main.c -o main.o
(-c는 링크 전까지만 실행하고, object 파일을 생성하라는 명령어임
이전까지는 -c라는 명령어가 없어 링크까지 거쳐 최종 실행파일이 생성됨)
4. FruitSaleSim1.cpp 분석(과일 판매자 및 구매자 클래스 상호작용 분석)
#include <iostream>
using namespace std;
class FruitSeller
{
private:
int APPLE_PRICE;
int numOfApples;
int myMoney;
public:
void InitMembers(int price, int num, int money)
{
APPLE_PRICE=price;
numOfApples=num;
myMoney=money;
}
int SaleApples(int money)
{
int num=money/APPLE_PRICE;
numOfApples-=num;
myMoney+=money;
return num;
}
void ShowSalesResult()
{
cout<<"남은 사과: "<<numOfApples<<endl;
cout<<"판매 수익: "<<myMoney<<endl<<endl;
}
};
class FruitBuyer
{
int myMoney; // private:
int numOfApples; // private:
public:
void InitMembers(int money)
{
myMoney=money;
numOfApples=0;
}
void BuyApples(FruitSeller &seller, int money)
{
numOfApples+=seller.SaleApples(money);
myMoney-=money;
}
void ShowBuyResult()
{
cout<<"현재 잔액: "<<myMoney<<endl;
cout<<"사과 개수: "<<numOfApples<<endl<<endl;
}
};
int main(void)
{
FruitSeller seller;
seller.InitMembers(1000, 20, 0);
FruitBuyer buyer;
buyer.InitMembers(5000);
buyer.BuyApples(seller, 2000);
cout<<"과일 판매자의 현황"<<endl;
seller.ShowSalesResult();
cout<<"과일 구매자의 현황"<<endl;
buyer.ShowBuyResult();
return 0;
}
1) using namespace std;
std::cout>> / std::cin<< / std::endl 등을 가지고 있는 std라는 이름공간에 접근할 때 생략하기 위해 using 사용
2) class FruitSeller{};
-
private로 클래스 내에서만 접근 가능한(생략가능, class는 기본적으로 private가 default이므로)
int APPLE_PRICE;
int numOfApples;
int myMoney;
-
public으로 어디서든 접근 가능한(생략불가)
void InitMembers(int price, int num, int money)
: 이 함수만을 통해서 class FruitSeller 내 private 변수들을 초기화
int SaleApples(int money)
: 이 함수만을 통해서 class FruitSeller 내 private 변수들을 조절하고, num을 return함
void ShowSalesResult()
: 이 함수만을 통해서 class FruitSeller 내 private 변수들의 상태를 출력함
3) class FruitBuyer{};
-
private로 클래스 내에서만 접근 가능한
int myMoney;
int numOfApples;
-
public으로 어디서든 접근 가능한
void InitMembers(int money)
: 이 함수만을 통해서 class FruitBuyer 내 private 변수들을 초기화
void BuyApples(FruitSeller &seller, int money)
: FruitSeller 클래스형의 변수만을 인수로 받음, 이 함수만을 통해서 class FruitBuyer 내 private 변수들을 조절함
void ShowBuyResult()
: 이 함수만을 통해서 class FruitBuyer 내 private 변수들의 상태를 출력함
4) int main(void)
FruitSeller seller;
: FruitSeller 클래스형 변수 seller 선언
seller.InitMembers(1000, 20, 0);
: FruitSeller의 public 함수인 InitMembers()를 통해 private 변수들을 1000원, 20개, 0원으로 초기화
FruitBuyer buyer;
: FruitBuyer 클래스형 변수 buyer 선언
buyer.InitMembers(5000);
: FruitBuyer의 public인 InitMembers()를 통해 private 변수를 5000원, 0개로 초기화
buyer.BuyApples(seller, 2000);
: FruitBuyer의 public인 BuyApples()의 FruitSeller 클래스형 변수 seller을 인수로 넘겨 seller 변수 안 public인 SaleApples()를 이용해 리턴 받은 num으로 private인 numOfApples는 개수가 증가, myMoney는 돈이 감소
seller.ShowSalesResult();
: seller 변수 안 public인 ShowSalesResult()를 이용하여 private인 변수들을 각각 출력
buyer.ShowBuyResult();
: buyer 변수 안 public인 ShowBuyResult()를 이용하여 private 변수들을 각각 출력
'LMS 7 > 개발일지' 카테고리의 다른 글
| 25.07.24 학습개발일지 / C++ (5) | 2025.07.29 |
|---|---|
| 25.07.23 학습일지 / C++ (3) | 2025.07.29 |
| 25.07.21 개발일지 / 채팅 프로그램 5팀 (1) | 2025.07.29 |
| 25.07.18 개발일지 / 채팅 프로그램 5팀 (3) | 2025.07.29 |
| 25.07.17 개발일지 / 채팅 프로그램 5팀 (0) | 2025.07.29 |