본문 바로가기

코딩/객체지향프로그래밍

[C++] 클래스와 객체 (1)

출처: https://www.guru99.com/java-oops-class-objects.html

 


 

1. 객체(Software Component) = 변수 + 함수

  • sw component = 변수 + 그 변수를 쉽게 사용할 수 있는 함수
  • 변수: ex) fstream안의 파일
  • 함수: ex) 파일을 다루기 위한 동작들 (open, close 등..)

 

2. 클래스(class)와 오브젝트(object)

  • 클래스: 추상화된 객체, 붕어빵 틀, 설계 도면 / ex)fstream myFile;
  • 오브젝트: 실체화(인스턴스화) 되고 정의된 객체, 붕어빵, 건물 / ex)fstream myFile;
  • (엄밀히 말하면) 클래스로부터 객체를 만들었다, 인스턴스를 만들었다!
  • 객체 = 클래스의 인스턴스(실체) → 실제로 사용하는, 변수와 같은 역할
  • [객체]와 [인스턴스]라는 용어는 상호 교환 가능하게 사용됨. (유동적으로)

 

3. 클래스 만들기

1. 순서

  1. 객체의 상태를 구성하는 데이터들을 지정한다. (멤버  변수 = 멤버 데이터)
  2. 객체의 행동에 대한 실행 코드를 정의한다.
  3. 객체가 클래스로부터 새로 만들어질 때 생성된 객체를 자동으로 초기화하는 코드를 정의한다.
  4. 클래스를 사용할 고객에게 보여지는 부분과 가려지는 부분을 나눈다.

2. 기본적인 틀

  1. class name{};
  2. private, public으로 영역을 분할 (접근 범위 지정, 영역 분할)
  3. private: (일반적으로) 영역에 멤버 데이터를 선언 / 클래스 내부에서만 사용 가능, 외부에서 호출 및 사용 불가
  4. public: (일반적으로) 영역에 멤버 함수(=메소드)를 선언 / 클래스 내부, 외부(ex) main) 에서 사용 가능
    • get(): 멤버 데이터를 외부로 반환
    • set(): 외부에서 멤버 데이터를 변경, 설정 (대표적인 클래스 메소드)
  5. 초기화: 생성자(constructor)를 통해
    • 모양: 리턴 타입이 없고, 생성자의 이름은 클래스의 이름과 동일
    • 기능: 객체가 선언될 때(만들어질 때) 멤버 데이터 초기화를 위해 1회 자동으로 호출
    • main함수에서 호출할 수 있는 메소드가 아님!!
    • 사용자가 생성자를 만들지 않으면(=사용자 정의) default constructor가 자동으로 만들어짐 (클래스이름(){})
    • 사용자가 생성자를 만들면 default constructor는 만들어지지 않음 default 생성자도 반드시 만들어줘야 함!!
  6. 인스턴스화 시: 일반적인 메소드들과는 다르게, 생성자는 { } / ( ) 혼용해서 사용 가능
    • ex) Account ac1{"홍길동", "1002", 5000}; = Account ac1("홍길동", "1002", 5000);
  7. (optional) 메소드를 선언부/정의부로 구분할 수 있음
    • 클래스 외부에 메소드 구현 시 함수 이름 앞에 [클래스이름]:: (범위 지정 연산자 '::' 이용)
    • 기능적 차이는 없음!

 

*) 3-1.~3-2 example 1 '2차원 평면 상의 점 클래스'

#include <iostream>
using namespace std;

class Point {
private:
	int x;
	int y;
public:
	Point(){ //사용자가 만든 default 생성자
		x = 0;
		y = 0;
	}
	Point(int _x, int _y) { //사용자가 만든 생성자
		x = _x;
		y = _y;
	}
	void setXY(int _x, int _y) {
		x = _x;
		y = _y;
	}
	int getX() { return x; }
	int getY() { return y; }
	void print() {
		cout << "(" << x << ", " << y << ")" << endl;
	}
};

int main() {
	Point pt1, pt2(10, 20); //클래스로부터 인스턴스화, 생성자가 1회 자동 호출
	pt1.setXY(1, 2);
//	cout << pt1.x << endl; 처럼 사용 못함->private이기 때문에
	cout << pt1.getX() << endl;
	cout << pt1.getY() << endl;

	pt1.print();
	pt2.print();

	return 0;
}

 

*) 3-1.~3-2. example 2 '계좌 클래스'

class Account {
private: //member data
	string name;
	string id;
	double balance;
public: //method
/*	//생성자1 (default)
	Account() {
		name = "xxx";
		id = "0000";
		balance = 0.0;
	}
	//생성자2
	Account(string _name, string _id, double _bal) {
		name = _name;
		id = _id;
		balance = _bal;
	}*/
    
	//생성자3 = 생성자1 + 생성자2
	Account(string _name = "xxx", string _id = "0000", double _bal = 0.0)
	:name(_name), id(_id), balance(_bal) {
	if (balance < 0)
		balance = 0; //통장 만들 때 바로 -일 수는 x
	}
    
	//3가지 함수의 선언부
	void print();
	void deposit(int _amt);
	bool withdraw(int _amt);
};
  • 생성자1: default 생성자, 클래스로부터 인스턴스화 시, 입력값을 주지 않을 때 default로 만들어진다. 이 때 멤버 데이터는 생성자의 body대로 초기화된다. ex) Account ac;
  • 생성자2: 클래스로부터 인스턴스화할 때 동시에 입력값을 지정해 멤버 데이터 값을 초기화할 수 있다. ex) Account ac("홍길동", "1002", 5000);
  • 생성자3: default argument + initialization list = 생성자 1 + 2 의 역할을 수행!!!! / '상속(inheritance)'할 때 initialization list로 초기화하는 방법을 많이 사용한다.
    • :멤버 데이터1(입력값1), 멤버 데이터2(입력값2), 멤버 데이터3(입력값3) { //body }
    • { 멤버 데이터1 = 입력값1; 멤버 데이터2 = 입력값2; 멤버 데이터3 = 입력값3; }
//클래스의 외부

//3가지 함수의 구현부
void Account::print() {
	cout << setw(10) << name
		<< setw(10) << id
		<< setw(10) << balance << endl;
}

void Account::deposit(int _amt) {
	balance += _amt;
}

bool Account::withdraw(int _amt) {
	int temp = balance - _amt;
	if (temp < 0)
		return false;
	else { //잔액이 출금하려는 금액보다 많을 때
		balance = temp;
		return true;
	}
}
  • 클래스의 멤버 function를 클래스 외부에서 구현 시 범위 지정 연산자 '::'로 함수의 소속을 명확히 해주기!
int main() {
	Account ac1("김철수", "1002", 5000); //생성자2 호출
	Account ac2; //생성자1 호출
	Account ac3("홍길동"); //default argument + initialization list로 입력값 1개라도 ok
	ac1.print();
	ac2.print();
	ac3.print();
	cout << endl;

	ac1.deposit(10000);
	ac1.print();
	cout << endl;

	if (!ac1.withdraw(1000000))
		cout << "Error:negative balance" << endl;

	if (ac1.withdraw(5000))
		ac1.print();
	cout << endl;

	vector<Account> vec1(10);//vector의 모든 10개의 원소는 Account형 객체!
	for (Account& elem : vec1) //simplified for문
//	for (auto& elem : vec1) 해도 ok (auto로 데이터 타입 자동 유추)
		elem.print();

	vector<Account> vec2{ Account("홍길동", "1234", 10000),
			      Account("이영희"),
			      Account("박지수") };

	return 0;
}

 

4. 캡슐화(Encapsulation)

클래스 내에서 접근 범위를 지정해 private, public 등의 키워드로 영역을 분할하는 것

 

가장 중요한 멤버 데이터들을 capsule로  싸고 메소드들로 빨대를 꽂음 → 메소드를 통해서 외부로 멤버 데이터를 반출하거나 외부 정보를 내부로 넣는다! (통로로서 사용하는 메소드)

 

C++에서는 private이 default이다. ('private'이라 안적어주면 컴파일러가 자동으로 private으로 이해함 !)

 

  • 소프트웨어 수정, 보완에 있어서 더 유연하게 대응할 수 있음.
  • 소프트웨어를 보다 신뢰할 수 있음.
  • 프로그래머가 소프트웨어 개발 프로세스를 보다 쉽게 이해하고 관리할 수 있음.

 


 

*)sample codes: https://github.com/halterman/CppBook-SourceCode

반응형

'코딩 > 객체지향프로그래밍' 카테고리의 다른 글

[C++] 상속  (0) 2020.08.06
[C++] 클래스와 객체 (2)  (0) 2020.08.04
[C++] 포인터, 벡터, 배열 (3)  (0) 2020.07.30
[C++] 포인터, 벡터, 배열 (2)  (0) 2020.07.29
[C++] 포인터, 벡터, 배열 (1)  (0) 2020.07.27