내가 정리할 개념들을 조금 나열해보겠다.
객체 지향이란 무엇인가?
구조체란 무엇인가?
클래스란 무엇인가?
생성자란 무엇인가?
연산자 오버로딩은 무엇인가?
키워드 friends 는 무엇인가?
참조자는 무엇인가?
위 개념들에 대해 정리를 할 것이다.
내가 2학년이나 돼서 C++을 배우는 것은 객체 지향을 이해하기 위해서이다. 세상은 객체로 되어있다. 사람이라는 개념으로 나는 구성되어 있고 또 구체적으로 대학생이라는 개념으로 되어있다.
프로그램도 이러한 객체(개념)로 구성하면 편하다. 한번 객체를 만들어 놓으면 코드를 재사용하기 쉽기 때문이다. 또 유지보수도 쉽다.
이러한 객체 지향에서 추상화 / 정보 은닉 / 캡슐화 / 상속 / 다형성 들을 공부해보자.
클래스와 비슷한 친구이다. 구조체 안에 함수는 넣을 수 없지만 변수들을 넣을 수 있다. 예를 들어서
struct CDAccountV1
{
double balance;
double interestRate;
int term;
};
이런식으로 만들어서
CDAccountV1 account;
account.balance;
account.interstRate;
account.term;
다음과 같은 식으로 선언과 접근을 한다.
초기화 팁!
CDAccountV1 account = {11.4, 0.4, 12};
이런식으로 하면 편하다.
내가 볼 땐 클래스가 구조체 상위호환인 것 같다. 클래스는 멤버변수도 있고 멤버 함수도 있다. 멤버 함수에 추상화를 잘 시켜 놓으면 그것이 객체 지향인 것이라고 생각한다. 또 정보를 드러낼 수도 있고 숨길 수도 있다.
class DayOfYear
{
public:
void output();
private:
int month;
int day;
};
void DayOfYear::output()
{
// private 이지만 함수 내부에서 접근해서 가능하다.
cout << month << "/" << day << endl;
}
다음과 같이 사용할 수 있다.
근데 여기서 변수를 초기화 시켜주고 싶은데 저 코드를 가져다가 DayOfYear.month = 2;하면 안된다. 그래서
accsssor를 만들어 주어서 사용한다.
void setDay(int d){day = d;}
void setMonth(int m) {month = m;}
다음과 같은 코드를 public 자리에 넣어주고
dy.setDay(28);
dy.setMonth(2);
다음과 같이 써주면 된다.
근데 위에 처럼 하는 건 조금 불편하다. 구조체를 초기화 했을 때처럼 한 줄로 초기화해주고 싶은데 아쉽다. 그래서 배우는 것이 생성자이다. 클래스에서 생성자를 따로 정의해주지 않으면 그냥 쓰레기 값으로 채워서 기본 생성자로 생성이 된다.
생성자는 굉장히 특별한 함수라서 조금 특이한 코딩 스타일을 가진다. 이 함수를 return을 하지 않는다는 특징도 가지고 있다.
class DayOfYear
{
public:
DayOfYear(int monhtVal, int dayVal);
DayOfYear(int monthVal);
DayOfYear();
void output();
private:
int year;
int day;
};
DayOfYear:: DayOfYear (int monthVal, int dayVal)
{
month = monthVal;
day = dayVal;
}
다음과 같이 선언 / 정의 한다. 근데 사실 저렇게 하기 조금 귀찮다. 그래서 조금 편하게 할 수 있는게 있다.
DayOfYear:: DayOfYear : month(monthVal), day(dayVal)
{};
DayOfYear:: DayOfYear : month(monthVal), day(1)
{};
DayOfYear:: DayOfYear : month(1), day(1)
{};
짱 편하다!
DayOfYear birthday(2, 28);
이런 식으로 구조체하고는 조금 다르지만 이렇게 써주면 된다.
왜인지는 모르겠는데 내가 지금까지 빼먹고 공부하고 있었다. ㅋㅋㅋ과제 점수 까인게 이것 때문인것 같다. 스태틱으로 선언하면 한번 선언되고 메모리가 끝날 때까지 다시 선언하지 않는다. 하지만 접근은 지역변수와 같은 접근만 허용한다. 하지만 메모리에 남아있기 때문에 그 값을 계속 업데이트 할 수 있다.
이것을 클래스에 사용하면 모든 객체가 이것을 공유할 수 있다고 한다. 놀랍다.
이걸 멤버 함수에도 사용해서 스태틱 함수로 만들어 줄 수도 있다.
지금부터 하는 것은 쉽지 않은 내용이다. 연산자를 클래스 끼리 할 수 있게 만들어주는 과정이다.
연산자 오버로딩을 하는 방법은 3가지가 있다. 클래스 밖에서 하거나 클래스 내부에서 하거나 friend를 써서 할 수 있다. 개인적으로 freind 를 쓰는게 아름다워 보인다.
외부에서 할 경우 다음과 같이 만든다.
const 클래스이름 operator +(const 클래스이름& 클래스1, const 클래스이름& 클래스2)
{
// 내가 생각하는 +의 연산
}
이런 식으로 연산자에 대해서 새롭게 정의하는 것이다. 여기서 나는 const가 왜 쓰이는 궁금했는데 그냥 값이 변경되지 말라고 붙는 것이라고 한다. 안 써도 동작하긴 한다.
특이한 연산자도 있다. ==의 경우에는 반환 형이 클래스가 아니라 bool형이다. 때문에 다음과 같이 사용한다.
bool operator == (const 클래스이름& 클래스1, const 클래스이름& 클래스2)
{
// 내가 생각하는 == 연산자.
}
아니면 단항 연산자도 있다.
const Money operator - (const Monay& class)
{
return Money(-class.getDollers(), -class.getCents());
}
이런식으로 써줄 수 있다.
클래스 내부에 써주는 방식도 있는데 다음과 같다.
const Money operator +(const Money& class1) const
{
return Money(dollers + class1.getDollers(), cents + class1.getCents());
}
다음과 같이 단항 연산자 마냥 사용한다.