본문 바로가기
Language&Framework&Etc/C++

클래스의 기본(03-3) 객체지향 프로그래밍의 이해

by 머리올리자 2020. 12. 24.

객체지향 프로그래밍의 이해

C++은 객체지향 언어.

 

객체 : Object → 사물, 또는 대상

 

즉, Object는 우리 주변에 존재하는 물건(연필, 나무, 지갑, 돈 등등)이나 대상(선생님, 교수님 등등)을 의미

 

그렇다면 객체를 지향하는 프로그래밍이란?

 

예시

 

"나는 과일장수에게 두 개의 사과를 구매했다!"

 

객체의 종류 : "나", "과일장수", "사과"

 

"나"라는 객체는 "과일장수"라는 객체로부터 "과일" 객체의 구매라는 액션을 취할 수 있어야 한다.

 

그러나 객체지향 프로그래밍에서는 "나" 그리고 "과일장수"와 같은 객체를 등장시킬 수 있을 뿐만 아니라,

"나"라는 객체가 "과일장수"라는 객체로부터 "과일" 객체를 구매하는 행위도 그대로 표현할 수 있다.

 

즉, 객체지향 프로그래밍은 현실에 존재하는 사물과 대상, 그리고 그에 따른 행동을 있는 그대로 실체화 시키는 형태의 프로그래밍

 


객체를 이루는 것은 데이터와 기능

프로그램상에 과일장수 객체가 존재한다고 가정

 

과일장수는 다음과 같은 형태를 띤다.

  • 과일을 판다
  • 사과 20개, 오렌지 10개를 보유하고 있다.
  • 과일판매 수익은 현재까지 50,000원

이 중 첫 번째는 과일장수의 '행동(behavior)'을 의미한다.

 

두 번째와 세 번째는 과일장수의 '상태(state)'를 의미.


이처럼 객체는 하나 이상의 상태 정보(데이터)와 하나 이상의 행동(기능)으로 구성이 되며,

상태 정보는 변수를 통해서 표현이 되고(변수에 상태 정보를 저장할 수 있으므로),

행동은 함수를 통해서 표현이 된다.


코드로 표현

 

상태 정보를 변수로

int numofapples; // -> 보유하고 있는 사과의 수
int mymoney;     // -> 판매 수익

과일장수의 행위인 과일의 판매를 함수로 표현

int saleapples(int money)  // 사과 구매액이 함수의 인자로 전달
{
	int num = money/1000;  // 사과 개당 1000원 가정
	numofapples -= num;    // 팔았기 때문에 사과의 수가 줄어들고,
	mymoney += money;      // 판매 수익 발생
	return num;            // 실제 구매가 발생한 사과의 수를 반환
}

'과일장수'의 정의와 멤버변수의 상수화에 대한 논의

객체를 생성하기에 앞서 객체의 생성을 위한 '틀(mold)'을 먼저 만들어야 한다.

 

이는 현실 세계에서 물건을 만들기 위해 틀을 짜는 행위.

 

'나' 또는 '과일장수' 객체를 생성하기 위해서는 이 둘을 위한 틀을 먼저 만들어야 한다.

class fruitseller
{
/* 변수 선언 */
private:
	int apple_price;
	int numofapples;
	int mymoney;

/* 함수 정의 */
public:
	int saleapples(int money)
	{
		int num = money/apple_price;
		numofapples -= num;
		mymoney += money;
		return num;
	}
}

 

과일장수의 틀 완성

#include <iostream>
using namespace std;
class fruitseller
{
private:
	int apple_price;
	int num_of_apples;
	int mymoney;
public:
	void init(int price, int num, int money)
	{
		apple_price = price;
		num_of_apples = num;
		mymoney = money;
	}
	int saleapples(int money)
	{
		int num = money / apple_price;
		num_of_apples -= num;
		mymoney += money;
		return num; // 판매한 과일 개수
	}
	void showresult()
	{
		cout << "남은 사과: " << num_of_apples << endl;
		cout << "판매 수익: " << mymoney << endl;

	}
};

'나(me)'를 표현하는 클래스의 정의

과일구매자인 '나(me)'를 표현하기 위한 클래스 정의

int numofapples; // -> 보유하고 있는 사과의 수
int mymoney;     // -> 소유하고 있는 현금의 액수

기능적인 측면에서 과일 구매자가 지녀야 할 기능은 '과일의 구매'

#include <iostream>
using namespace std;
class fruitbuyer
{
	int num_of_apples; // private:
	int mymoney;	   // private:
public:
	void init(int money)
	{
		num_of_apples = 0;
		mymoney = money;
	}
	void buyapples(fruitseller &seller, int money)
	{
		num_of_apples += seller.saleapples(money);
		mymoney -= money;
	}
	void showresult()
	{
		cout << "현재 잔액: " << mymoney << endl;
		cout << "사과 개수: " << num_of_apples << endl;
	}
};

 

위 클래스에 선언된 두 변수 mymoney와 num_of_apples에는 private이나 public과 같은 접근 제어 지시자가 없음,

 

그러나 클래스는 아무런 선언이 존재하지 않을 때 private으로 간주된다는 것을 기억(구조체는 public)

 

즉, 이 둘은 private이다(구조체였다면 public).

 


클래스 기반의 두 가지 객체생성 방법

혹시 객체를 생성하지 않고, 이 두 클래스 안에 존재하는 변수에 전급하고, 함수를 호출하는 것이 가능? ---> X

 

불가능함. 이들은 '실체(객체)'가 아닌 '틀'이다. 따라서 접근도 호출도 불가능하다.

 

이는 자동차의 엔진과 자동차의 외형을 생산할 수 있는 틀이 있다고 해서, 이들을 타고 달릴 수 없는 것과 같음.

 

우리가 해야 할 일은 앞서 정의한 클래스를 실체화.

 

즉, 객체화시키는 것.

 

C++에서 정의하고 있는 두 가지 객체생성 방법이 있음

 

classname objname;                    // 일반적인 변수의 선언방식
classname *ptrobj = new classname;    // 동적 할당방식(힙 할당방식)

기존에 정의한 클래스 방식

fruitseller seller;
fruitbuyer byuer;

동적할당 방식

fruitseller * objptr1 = new fruitseller;
fruitbuyer * objptr2 = new fruitbuyer;

사과장수 시뮬레이션!

#include <iostream>
using namespace std;
class fruitseller
{
private:
	int apple_price;
	int num_of_apples;
	int mymoney;
public:
	void init(int price, int num, int money)
	{
		apple_price = price;
		num_of_apples = num;
		mymoney = money;
	}
	int saleapples(int money)
	{
		int num = money / apple_price;
		num_of_apples -= num;
		mymoney += money;
		return num; // 판매한 과일 개수
	}
	void showresult()
	{
		cout << "남은 사과: " << num_of_apples << endl;
		cout << "판매 수익: " << mymoney << endl << endl;

	}
};

#include <iostream>
using namespace std;
class fruitbuyer
{
	int num_of_apples; // private:
	int mymoney;	   // private:
public:
	void init(int money)
	{
		num_of_apples = 0;
		mymoney = money;
	}
	void buyapples(fruitseller& seller, int money)
	{
		num_of_apples += seller.saleapples(money);
		mymoney -= money;
	}
	void showresult()
	{
		cout << "현재 잔액: " << mymoney << endl;
		cout << "사과 개수: " << num_of_apples << endl << endl;
	}
};

int main(void)
{
	fruitseller seller;
	fruitbuyer buyer;
	seller.init(1000, 20, 0);
	buyer.init(5000);

	buyer.buyapples(seller, 2000);

	cout << "과일 판매자의 현황" << endl;
	seller.showresult();
	cout << "과일 구매자의 현황" << endl;
	buyer.showresult();
	return 0;
}

 


객체간의 대화 방법(Message Passing 방법)

위의 코드를 보면 fruitbuyer 객체에 존재하는 함수 내에서 fruitseller 객체의 함수 saleapples를 호출하고 있다.

 

이 문장은 다음의 의미와 같다.

 

"seller님, 사과 2,000원어치만"

 

이는 객체지향에서 매우 중요한 의미.

 

'나'라는 객체가 '과일장수'라는 객체로부터 '과일' 객체를 구매하는 행위도 그대로 표현할 수 있다.

 

이처럼 하나의 객체가 다른 하나의 객체에게 메세지를 전달하는 방법은(어떠한 행위의 요구를 위한 메시지 전달) 함수호출을 기반으로 한다.

 

그래서 객체지향에서는 이러한 형태의 함수호출을 가리켜 '메시지 전달(Message Passing)' 이라 한다.

 

 

참고 : [윤성우 열혈 C++ 프로그래밍] - 대부분의 내용 및 코드는 이 책에서 개인 공부 정리 목적으로 참고하였습니다.