1. 객체(Software Component) = 변수 + 함수
- sw component = 변수 + 그 변수를 쉽게 사용할 수 있는 함수
- 변수: ex) fstream안의 파일
- 함수: ex) 파일을 다루기 위한 동작들 (open, close 등..)
2. 클래스(class)와 오브젝트(object)
- 클래스: 추상화된 객체, 붕어빵 틀, 설계 도면 / ex)fstream myFile;
- 오브젝트: 실체화(인스턴스화) 되고 정의된 객체, 붕어빵, 건물 / ex)fstream myFile;
- (엄밀히 말하면) 클래스로부터 객체를 만들었다, 인스턴스를 만들었다!
- 객체 = 클래스의 인스턴스(실체) → 실제로 사용하는, 변수와 같은 역할
- [객체]와 [인스턴스]라는 용어는 상호 교환 가능하게 사용됨. (유동적으로)
3. 클래스 만들기
1. 순서
- 객체의 상태를 구성하는 데이터들을 지정한다. (멤버 변수 = 멤버 데이터)
- 객체의 행동에 대한 실행 코드를 정의한다.
- 객체가 클래스로부터 새로 만들어질 때 생성된 객체를 자동으로 초기화하는 코드를 정의한다.
- 클래스를 사용할 고객에게 보여지는 부분과 가려지는 부분을 나눈다.
2. 기본적인 틀
- class name{};
- private, public으로 영역을 분할 (접근 범위 지정, 영역 분할)
- private: (일반적으로) 영역에 멤버 데이터를 선언 / 클래스 내부에서만 사용 가능, 외부에서 호출 및 사용 불가
- public: (일반적으로) 영역에 멤버 함수(=메소드)를 선언 / 클래스 내부, 외부(ex) main) 에서 사용 가능
- get(): 멤버 데이터를 외부로 반환
- set(): 외부에서 멤버 데이터를 변경, 설정 (대표적인 클래스 메소드)
- 초기화: 생성자(constructor)를 통해
- 모양: 리턴 타입이 없고, 생성자의 이름은 클래스의 이름과 동일
- 기능: 객체가 선언될 때(만들어질 때) 멤버 데이터 초기화를 위해 1회 자동으로 호출됨
- main함수에서 호출할 수 있는 메소드가 아님!!
- 사용자가 생성자를 만들지 않으면(=사용자 정의) default constructor가 자동으로 만들어짐 (클래스이름(){})
- 사용자가 생성자를 만들면 default constructor는 만들어지지 않음 → default 생성자도 반드시 만들어줘야 함!!
- 인스턴스화 시: 일반적인 메소드들과는 다르게, 생성자는 { } / ( ) 혼용해서 사용 가능함
- ex) Account ac1{"홍길동", "1002", 5000}; = Account ac1("홍길동", "1002", 5000);
- (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 |