C++ 에서의 구조체
구조체의 등장 배경
- 연관 있는 데이터를 하나로 묶으면 프로그램의 구현 및 관리가 용이
- 구조체는 연관 있는 데이터를 하나로 묶는 문법정 장치
연관 있는 데이터들은 생성 및 소멸의 시점이 일치하고, 이동 및 전달의 시점 및 방법이 일치하기 때문에 하나의 자료형으로 묶어서 관리하는 것이 용이하다.
C++ 에서의 구조체 변수 선언
// C 구조체 변수 초기화
struct Car basicCar;
struct Car simpleCar;
-------------------------------------
// C++ 구조체 변수 초기화
Car basicCar;
Car simpleCar;
C++ 에서는 구조체 변수 선언시 struct 키워드의 생략을 위한 typedef 선언이 불필요
struct Car
{
char gamerID[ID_LEN]; // 소유자 ID
int fuelGauge; // 연료량
int curSpeed; // 현재속도
};
void ShowCarState(const Car &car)
{
...
}
void Accel(Car &car)
{
...
}
void Break(Car &car)
{
...
}
데이터 뿐만 아니라, 해당 데이터와 연관된 함수 모임들도 함께 그룹을 형성하기 때문에 함수도 하나로 묶는 것에 대해 나름의 가치를 부여할 수 있다
구조체 안에 함수 삽입하기
struct Car
{
char gamerID[ID_LEN];
int fuelGauge;
int curSpeed;
void ShowCarState(const Car &car)
{
...
}
void Accel(Car &car)
{
// 상위에 선언된 구조체 변수에 접근
cout << "소유자ID: " << gamerID << endl;
cout << "연료량: " << fuelGauge << "%" << endl;
cout << "현재속도: " << curSpeed << "km/s" << endl << endl;
}
void Break(Car &car)
{
if (curSpeed < BRK_STEP)
{
// 상위에 선언된 구조체 변수에 접근
curSpeed = 0;
return ;
}
curSpeed -= BRK_STEP;
}
}
이렇게 구조체 내에서 함수를 정의하면, 외부에서 구조체를 통해 함수를 호출할 수 있다
구조체 내에서 정의된 함수는 inline 선언된 것으로 간주되어 컴파일 과정에서 inline 화 한다.
Car myCar;
myCar.ShowCarState();
myCar.Accel();
myCar.Break();
C++에서는 구조체 안에 함수를 삽입하는 것이 가능하다. 따라서 C++ 에서는 구조체가 아닌, 클래스라 한다.
실제로 cppreference.com 에서도
"A class defined with the keyword class has private access for its members and its base classes by default.
A class defined with the keyword struct has public access for its members and its base classes by default."
'구조체 키워드로 정의된 클래스는' .... 이라고 표현하고 있다.
C++ 에서의 구조체 변수 선언
실제로는 구조체 변수마다 함수가 독립적으로 존재하는 구조는 아니다.
그러나 논리적으로는 독립적으로 존재하는 형태로 보아도 문제가 없으니, 위의 그림의 형태로 변수(객체)를 이해하자
(C 로 비유하자면 같은 함수를 각각의 변수에 적용시킨 것과 유사)
구조체 안에 enum 상수의 선언
// Car 클래스를 위해 정의된 상수, 기존 define 방식
#define ID_LEN 20
#define MAX_SPD 200
#define FUEL_STEP 2
#define ACC_STEP 10
#define BRK_STEP 10
-----------------------------------------------------------
// namespace 를 활용하는 방식
namespace CAR_CONST
{
enum
{
ID_LEN = 20,
MAX_SPD = 200,
FUEL_STEP = 2,
ACC_STEP = 10,
BRK_STEP = 10
};
}
------------------------------------------------------------
// 구조체를 활용하는 방식
struct Car
{
enum
{
ID_LEN = 20,
MAX_SPD = 200,
FUEL_STEP = 2,
ACC_STEP = 10,
BRK_STEP = 10
};
char gamerID[ID_LEN];
int fuelGauge;
int curSpeed;
void ShowCarState() { ... }
void Accel() { ... }
void Break() { ... }
}
구조체 안에 enum 을 선언을 둠으로써 잘못된 외부의 접근을 제한할 수 있다.
함수는 외부로 뺄 수 있다.
struct Car
{
...
void ShowCarState();
void Accel();
void Break();
...
}
void Car::ShowCarState() { ... }
void Car::Accel() { ... }
void Car::Break() { ... }
-----------------------------------------
// 함수 내 정의가 inline 적용이 되니 외부 정의시 inline 을 명시해서 사용하는 것을 권장!!!
inline void Car::ShowCarState() { ... }
inline void Car::Accel() { ... }
inline void Car::Break() { ... }
클래스와 구조체의 유일한 차이점
class Car
{
char gamerID[ID_LEN];
int fuelGauge;
int curSpeed;
void ShowCarState() { ... }
void Accel() { ... }
void Break() { ... }
}
int main(void)
{
Car run99;
strcpy(run99.gamerID, "run99"); // 무효, 접근불가
run99.fuelGauge=100; // 무효, 접근불가
run99.curSpeed=0; // 무효, 접근불가
...
}
단순히 키워드만 class로 바꾸면 선언된 멤버의 접근이 불가능하다.
따라서 별도의 접근제어와 관련된 선언을 추가 해야 한다.
접근제어 지시자
- public : 어디서든 접근허용
- protected : 상속관계에 놓여있을 때, 유도 클래스에서의 접근 허용
- privare : 클래스 내(클래스 내에 정의된 함수)에서만 접근허용
class Car
{
private:
char gamerID[CAR_CONST::ID_LEN];
int fuelGauge;
int curSpeed;
public:
void InitMembers(char *ID, int fuel);
void ShowCarState();
void Accel();
void Break();
};
int main(void)
{
Car run99;
run99.InitMembers("run99", 100);
run99.Accel();
run99.Accel();
run99.Accel();
void ShowCarState();
void Break();
void ShowCarState();
return 0;
}
Car의 멤버함수는 모두 public이므로 클래스의 외부에 해당하는 main 함수에서 접근가능하다.
용어정리: 객체(Object), 멤버변수, 멤버함수
class Car
{
private:
char gamerID[CAR_CONST::ID_LEN];
int fuelGauge;
int curSpeed; // Car 클래스 내부에서 생성된 변수를 '멤버변수' 라고 한다.
public:
void InitMembers(char *ID, int fuel);
void ShowCarState();
void Accel();
void Break(); // Car 클래스 내부에서 정의/선언된 함수를 '멤버함수' 라고 한다.
};
int main(void)
{
Car run99; // Car 클래스 대상으로 생성된 변수는 '객체' 라고 한다.
...
}
C++ 에서의 파일 분할
class Car
{
private:
char gamerID[CAR_CONST::ID_LEN];
int fuelGauge;
int curSpeed;
public:
void InitMembers(char *ID, int fuel);
void ShowCarState();
void Accel();
void Break();
};
클래스의 선언은 일반적으로 헤더파일에 삽입한다. 객체생성문 및 멤버의 접근문장을 컴파일하기 위해서 필요하다.
클래스의 이름을 때서 Car.h로 헤더파일의 이름정의하기도 한다.
단! '인라인 함수'는 컴파일 과정에서 함수의 호출문을 대체해야 하기 때문에 헤더파일에 함께 정의되어야 한다
void Car::InitMembers(char *ID, int fuel) { ... }
void Car::ShowCarState() { ... }
void Car::Accel() { ... }
void Car::Break() { ... }
Car 클래스의 멤버함수의 몸체는 다른 코드의 컴파일 과정에서 필요한 게 아니다.
링크의 과정을 통해서 하나의 바이너리로 구성만 되면 된다. 따라서 cpp 파일에 정의하는 것이 일반적이다.
클래스의 이름을 따서 Car.cpp로 소스파일의 이름을 정의하기도 한다.
객체지향 프로그래밍의 이해
객체에 대한 간단한 정의
- 사전적 의미 : 물건 또는 대상
- 객체지향 프로그래밍 : 객체 중심의 프로그래밍
객체지향 프로그래밍에서는 '나', '과일장수', '사과'라는 객체를 등장시켜서 두 개의 사과 구매라는 행위를 실체화한다.
객체지향 프로그래밍은 현실에 존재하는 사물과 대상, 그리고 그에 따른 행동을 있는 그대로 실체화시키는 형태의 프로그래밍이다.
객체를 이루는 것은 데이터와 기능
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;
}
}
class FruitBuyer
{
int myMoney; // private
int numOfApples // private
// 따로 private 선언을 하지 않아도 기본 private 적용이나 웬만하면 private 선언해 줄 것을 권장
public:
void InitMembers(int money)
{
myMomey = momey;
numOfApples = 0;
}
void BuyApples(FruitSeller &seller, int money)
{
numOfApples += seller.SaleApples(money);
myMoney -= money;
}
void ShowBuyResult()
{
cout << "현재 잔액: " << myMoney << endl;
cout << "사과 개수: " << numOfApples << 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;
}
'과일장수'의 정의와 멤버변수의 상수화
즉, 값이 정해지지 않은 상태에서의 const 상수화는 어렵다는 내용
‘나(me)’를 표현하는 클래스의 정의와 객체생성
사과장수 시뮬레이션 완료
'C++ > 윤성우의 열혈 프로그래밍 C++' 카테고리의 다른 글
윤성우의 열혈 C++ chpt6. (2) | 2025.06.08 |
---|---|
윤성우의 열혈 C++ chpt5. (0) | 2025.05.16 |
윤성우의 열혈 C++ chpt3. (0) | 2025.05.12 |
윤성우의 열혈 C++ chpt2. (0) | 2025.05.11 |
윤성우의 열혈 C++ chpt1. (0) | 2025.05.11 |