열혈 C++ 복습 3
♨ 개인적 해석이 들어간 글임으로, 인지하지 못한 오류가 있을 수 있습니다 ♨
교재 - <윤성우 열혈 C++ 프로그래밍>
▣ C++에서의 구조체
- 구조체의 등장배경
연관 있는 데이터를 하나로 묶어서 프로그램의 구현/관리를 용이하게 하기 위해
-> 구조체 = 연관있는 데이터를 묶을 수 있는 문법적 장치
cf) 소프트웨어 = 데이터의 표현 + 데이터의 처리
- C++에서의 구조체 변수 선언
C언어에서 구조체 변수 : struct Car basicCar; ( Car라는 이름의 구조체, 그 구조체 변수 basicCar)
-> struct를 넣어 자료형이 구조체를 기반으로 정의되어있음을 알려줘야 한다
struct를 생략하고 싶다면 별도의 typedef 선언을 추가해야 한다
=> C++에서는 별도의 typedef 선언없이 구조체 변수를 선언할 수 있다
예) Car basicCar;
함수 = 데이터의 처리를 담당하는 도구
∴ 데이터와 함께 부류를 형성한다
-> ShowCarState / Accel / Break
이 3가지 함수는 구조체 Car와 함께 부류를 형성하여, Car와 관련된 데이터의 처리를 담당하는 함수
∴ 이 함수들은 Car에 종속적이다
그러나! 전역함수이기 때문에 Car 종속적인 성격을 보여주지 못하고 다른 영역에서 함수를 호출하는 것도 가능한 상황
-> C++에서는 구조체 안에 함수 선언/정의가 가능하다
- 구조체 안에 enum 상수의 선언
앞서 나온 코드에서 나온 매크로 상수(예- #define ID_LEN)는 구조체 Car에만 의미있는 상수
-> 다른 곳에서 사용되지 않으니, Car에 종속적인 함수처럼 구조체 내에 포함되어 있는 것이 좋다
이때 열거형 enum을 이용
- 이름공간(namespace)을 사용하여 상수가 사용되는 영역을 표시할 수도 있다
- 구조체 내에 정의된 함수의 길이가 너무 길다면
-> 함수의 선언만 구조체 내에 해주고, 정의를 구조체 밖에서 해줄 수 있다
그러면 구조체 내에 존재하는 함수가 한눈에 보인다(구조체 분석에 편하다)
※ 구조체 안에 함수가 정의되어 있으면 인라인 처리가 된다!
-> 하지만 위와 같이 구조체 밖으로 함수의 정의부를 빼면 그 의미가 사라지므로
필요하다면 명시적으로 인라인 처리를 지시해야한다
예)
▣ 클래스(Class)와 객체(Object)
- 클래스와 구조체의 차이점
이 둘의 코드상 차이는 키워드를 struct로 적느냐 와 class로 적느냐 뿐이다
-> 그러나 class 변수는 구조체 변수처럼 초기화하지 못한다
∴ Car run99 = { "run99", 100, 0 }이 struct면? (O)
class면? (X)
-> 클래스는 별도의 선언이 없다면, 클래스 내부에 선언된 변수는 클래스 내부에 선언된 함수에서만 접근이 가능하다
∴ 클래스를 정의하는 과정에서 접근 허용범위를 선언해주어야 한다
- 접근제어 지시자(접근제어 레이블)
C++의 접근제어 지시자 : public / protected / private
public : 어디서든 접근 허용
protected : 상속관계에 있을 때, 유도 클래스에서의 접근 허용
private : 클래스 내(클래스 내부에 정의된 함수)에서만 접근 허용
위의 구조체로 된 코드를 접근제어 지시자를 포함한 클래스로 변경하면
-> 정리
1. 접근제어 지시자 A가 선언되면, 그 이후에 등장하는 변수/함수는 A에 해당하는 범위 내에서 접근이 가능하다
2. 새로운 접근제어 지시자 B가 선언되면, 그 이후로 등장하는 변수/함수는 B에 영향을 받는다
3. 함수의 정의가 밖에 있더라도, 함수의 선언부가 클래스 내에 있기 때문에 클레스의 일부로 본다
-> 클래스 내부로 인정되기 때문에 함수 내에서 private 변수/함수에 접근이 가능하다
4. 구조체는 별도의 접근제어 지시자가 없다면, 그 내에 있는 모든 변수/함수는 public으로 선언된다
5. 클래스는 별도의 접근제어 지시자가 없다면, 그 내에 있는 모든 변수/함수는 private으로 선언된다
6. 접근제어 지시자는 세미콜론( ; )이 아닌 콜론( : )이 붙는데, 이는 접근제어 지시자가 특정 위치정보를 알리는
레이블(라벨)이기 때문이다 + switch문의 case도 레이블이기에 : 이 붙는다
- 객체(Object), 멤버변수, 멤버함수
멤버변수 : 클래스 내에 선언되어, 클래스를 구성하는 변수
멤버함수 : 클래스 내에 선언되어, 클래스를 구성하는 함수
예) 이전에 나온 Car 클래스에서 멤버변수 = char gameID[CAR_CONST::ID_LEN] / int fuelGauge / int curSpeed
멤버함수 = void InitMembers(char * ID, int fuel) / void ShowCarstate() /
void Accel() / void Break()
- C++에서의 파일분할
Car.h : 클래스의 선언을 담는다
-> 클래스의 선언 = 클래스에 대한 정보, 클래스를 구성하는 외형적인 틀 (선언과 다른부분 = 오류)
Car.cpp : 클래스의 정의(멤버함수의 정의)를 담는다
-> 정의부는 다른 문장의 컴파일에 필요한 정보를 갖지 않기 때문에
컴파일 된 후 링커에 의해 하나의 실행파일로 묶이기만 하면 된다
main함수 부분
- 인라인함수는 헤더파일에 있어야 한다
인라인 함수는 컴파일 과정에서 "함수의 호출 문이 있는 곳에 함수의 몸체 부분이 삽입되어야" 하기 때문에
인라인 함수는 정의부까지 헤더파일에 있어야 한다
예)
-> 에러를 수정하려면 선언과 함께 정의를 헤더파일에서 해주면 된다
▣ 객체지향 프로그래밍의 이해
- 객체지향 프로그래밍 = 객체(Object, 현실에 존재하는 사물과 대상)와
그 객체의 행동을 실체화 시키는 형태의 프로그래밍
예) 나는 과일장수에게 두 개의 사과를 구매했다
-> 나/ 과일장수 / 사과 : 모두 가 객체
- 객체를 이루는 것은 데이터와 기능이다
-> 과일 장수의 행동 : 과일의 판매
과일의 판매를 중점에 두고 과일 장수라는 객체를 프로그램화 하면
1. 과일장수는 과일을 판다
2. 과일장수는 사과 10개, 오랜지 10개를 보유하고 있다
3. 과일장수가 보유한 현금은 50,000원이다
-> 1 = 과일장수의 행동
2, 3 = 과일장수의 상태
∴ 객체 = 하나 이상의 상태 정보(데이터) + 하나 이상의 행동(기능)
-> 상태 정보는 변수로 / 행동은 함수로 표현된다
이를 토대로 2번을 변수로 표현하면
보유한 사과의 수 : int numOfApples
보유한 오랜지 수 : int numOfOranges
보유한 현금 : int CurMoney
1번을 함수로 표현한다면
- 과일장수 객체의 정의와 멤버변수의 상수화
과일장수 클래스의 정의(헤더파일) = 과일장수 객체의 틀
-> 과일장수의 상태나 행동을 추가하려면 틀에 추가
예)
-> 이때 사과의 판매가격을 일정하게 유지하고자 한다
그러나 상수화는 선언과 동시에 초기화를 해야하나, 클래스의 멤버변수 선언시 초기화까지 하는 것이 불가능하다
- 나(과일구매자)를 표현하는 클래스 정의
FruitBuyer에게 필요한 상태와 행동은 소유금, 소유한 과일 수, 구매 행위 등이 있다
- 클래스 기반의 두 가지 객체 생성 방법
객체 생성 없이(이전의 표현으론 클래스 변수) 클래스 내부의 함수나 변수에 접근할 수 없다
-> 클래스의 실체화 = 클래스의 객체화하여야 한다
예) Car car; // 일반적인 변수 선언 방식
Car * ptrCar = new Car; // 동적 할당 방식(힙 할당 방식)
-> 일반화하기
일반적 변수 선언 : 클래스이름 변수이름;
동적 할당 방식 : 클래스이름 * 변수이름 = new 클래스이름;
- 앞서 나온 과일가계에서의 예시(판매자/구매자)를 합쳐 완성하기
- 객체간 대화 방법(Message Passing)
하나의 객체가 다른 하나의 객체와 소통하는 방법은 함수호출을 기반으로 한다
예) 나(Buyer)가 과일장수(Seller)에게 소통하기 위해서
Buyer 내부의 BuyApples함수와 그 매개변수로 쓰인 객체(seller)를 이용하였다
-> 함수를 이용해 객체와 접근하였다!
둘 이상의 객체간의 소통을 위한 함수호출을 '메시지 전달(Message Passing)'이라고 한다
연습문제
▣ 3-1 구조체 내에 함수정의하기
2차원 평면상에서의 좌표를 표현할 수 있는 구조체를 다음과 같이 정의하였다
struct Point
{
int xpos;
int ypos;
};
위의 구조체를 기반으로 다음의 함수를 정의하고자 한다 (자세한 기능은 실행의 예를 통해서 확인한다)
- void MovePos(int x, int y); : 점의 좌표이동
- void AddPoint(const Point &pos); : 점의 좌표증가
- void ShowPosition(); : 현재 x, y 좌표정보 출력
단, 위의 함수들을 구조체 안에 정의를 해서 다음의 형태로 main 함수를 구성할 수 있어야 한다
int main(void)
{
Point pos1 = { 12, 4 };
Point pos2 = { 20, 30 };
pos1.MovePos(-7, 10);
pos1 ShowPosition(); // [5, 14] 출력
pos1.AddPoint(pos2);
pos1.ShowPostion(); // [25, 44] 출력
return 0;
}
▣ 3-2 클래스의 정의
1. 계산기 기능의 Calculator 클래스를 정의하라
- 기본기능 : 덧셈, 뺄셈, 곱셉, 나누셈
- 연산시 어떤 연산을 몇번 했는지 기록
- 단 멤버변수는 private으로, 멤버함수는 public으로 선언
- main 함수 예시
int main (void)
{
Calculator cal;
cal.Init();
cout << "3.2 + 2.4 = " << cal.Add(3.2 2.4) << endl;
cal.ShowOpCount();
return 0;
}
2. 문자열 정보를 내부에 저장하면 Printer라는 이름의 클래스를 디자인하라
- 클래스의 두 가지 기능은 문자열 저장 / 문자열 출력
int main (void)
{
Print pnt;
pnt.SetString("Hello world!);
pnt.ShowString();
return 0;
}