팁: 프로그래머의 실수에 대한 대책이 준비되어 있어야 한다.
-> 제한된 방법으로의 접근만 허용을 해서 잘못된 값이 저장되지 않도록 도와야 하고, 또 실수를 했을 때, 실수가 쉽게 발견되도록 해야 한다.
변경되기 쉬운 멤버변수를 private으로 선언하고, 해당 변수에 접근하는 함수를 별도로 정의해서, 안전한 형태로 멤버 변수의 접근을 유도하는 것이 바로 '정보 은닉'
이며, 이는 좋은 클래스가 되기 위한 기본조건이 된다.
const
함수
int GetX() const;
와 같이 const 선언이 추가된 함수들은 class
안 쪽의 맴버변수의 값을 변경하지 않겠다는 선언이다.
const
함수 내에서는 const
가 아닌 함수의 호출이 제한된다.
함수의 매개변수로 const
참조자가 있는 경우 이 const
참조자를 대상으로 값의 변경 능력을 가진 함수 호출을 허용하지 않는다.(실제 값의 변경여부에 관계없이)
EX)
class EasyClass
{
private:
int num;
public:
int GetNum()
{
return num;
}
};
class LiveClass
{
private:
int num;
public:
void InitNum(const EasyClass &easy){
num = easy.GetNum(); // 컴파일 에러 발생! -> const 참조자가 붙은 매개변수(객체)는 const 함수 호출만 가능하다!
// 맴버가 변경되면 안되기 때문!
}
}
캡슐화란 관련 있는 함수와 변수를 하나의 클래스 안에 묶는 것이다.
캡슐화는 하나의 클래스로만 모든 것을 구성해야 하는 것은 아니고, 다른 클래스를 활용해도 된다.
어떻게 구성을 하느냐가 아니고, 어떠한 내용으로 구성을 하느냐에 있다.
캡슐화는 어려운 개념으로, 캡슐화의 범위를 결정하는 일이 쉽지 않기 때문
생성자의 이해
위와 같은 유형을 생성자 (constructor)
라 하며, 객체 생성시 딱 한번 호출된다.
보통 함수의 원형은 전역적으로(함수 밖에) 선언하지만, 함수 내에 지역적으로 선언이 가능하다.
class SimpleClass {
private:
int num1;
int num2;
public:
SimpleClass(int n1, int n2) {
num1 = n1;
num2 = n2;
}
int GetNum1() const {
return num1;
}
void showData() const {
cout << num1 << ' ' << num2 << endl;
}
};
int main(int argc, char** argv)
{
SimpleClass sc1();// 함수 원형 선언!
SimpleClass mysc = sc1();
mysc.showData();
return 0;
}
SimpleClass sc1() {
SimpleClass sc(20, 30);
return sc;
}
따라서, class 객체 생성시 매개변수가 없는 생성자일지라도 함수 원형 선언과 구분되게 하기 위해 SimpleClass sc()
와 같은 형태는 지원이 안된다. SimpleClass sc
형태로 만들자
class Point {
public:
int x;
int y;
Point(const int& x1, const int& y1) {
x = x1; y = y1;
}
};
class Rectangle
{
public:
Rectangle(const int& x1, const int& y1, const int& x2, const int& y2);
void ShowRecInfo() const;
private:
Point upLeft;
Point lowRight;
};
Rectangle:: Rectangle(const int& x1, const int& y1, const int& x2, const int& y2)
:upLeft(x1, y1), lowRight(x2,y2) // 맴버 이니셜라이져를 이용한 경우
{
//empty
}
위의 :upLeft(x1, y1), lowRight(x2,y2)
가 의미하는 바는 아래와 같다.
멤버 이니셜라이져를 이용해서 변수 및 const 상수(변수) 초기화가 가능하다.
ex)
class Point {
public:
const int x;
int y;
Point(const int& x1, const int& y1) : x(x1)//:x(x1)은 멤버 이니셜라이저를 통해 선언과 동시 초기화가 이뤄지는 바이너리 코드로 짜여져
//int x = x1과 같은 형태가 된다. 따라서 생성자에서 초기화가 가능하다!
{
//x = x1; -> x가 const 상수 이므로 이 구문은 컴파일 에러가 뜬다!
y = y1;
}
};
아래의 이유로, 되도록이면 멤버 변수 초기화에 있어서는 생성자의 몸체가 아닌 멤버 이니셜라이저를 사용하라.
객체의 생성과정
디폴트 생성자(Default Constructor)
private 생성자
소멸자의 이해와 활용
~
가 붙은 형태의 이름을 갖는다.void
형으로 선언되어야 하기 때문에 오버로딩, 디폴트 값 설정 등이 불가능하다.class SimpleClass {
private:
int num1;
int num2;
public:
SimpleClass(int n1, int n2) {
num1 = n1;
num2 = n2;
}
int GetNum1() const {
return num1;
}
void showData() const {
cout << num1 << ' ' << num2 << endl;
}
SimpleClass& adder(int n) { //이런식으로 자기 자신에 대한 참조자를 반환 가능하다.
num1++;
return *this;
}
};
int main(){
int num = 8;
int &ref = num;
}
이때, ref에는 num의 정수값이 대입되는 것이 아니다.
변수 num을 참조 할 수 있는 참조의 정보가 전달된다.
즉, 변수 num을 참조할 수 있는 참조 값이 참조자 ref에 전달되어, ref가 변수num을 참조 할 수 있게 된다.