본문 바로가기
코스웨어/16년 스마트컨트롤러

2016-09-25_조재찬_스터디일지_CPP-정보은닉, const함수, 캡슐화

by 알 수 없는 사용자 2016. 9. 25.
728x90
반응형

정보 은닉 (Information)

클래스의 멤버변수를 private로 선언, 해당 변수에 접근하는 함수를 별도로 정의해, 

 안전한 형태로 멤버 변수의 접근을 유도한다.


Point 클래스의 정보은닉

1
2
3
4
5
6
7
8
9
10
11
12
13
class Point
{
private:
    int x; 
    int y;    
 
public:
    bool InitMembers(int xpos, int ypos);
    int GetX() const;
    int GetY() const;
    bool SetX(int xpos);
    bool SetY(int ypos);
};
cs

8 행 : 벗어난 범위의 값 저장을 막는 초기화 함수

9-12 행 : 정보 은닉으로 인해 추가되는 접근(access) 함수들 


get은 값을 반환, set은 값을 저장하는 함수로 엑세스 함수를 추가하는 것이 일반적


1
2
3
4
5
6
7
8
9
10
11
bool Point::SetX(int xpos)
{
    if(0>xpos || xpos>100)
    {
        cout<<"벗어난 범위의 값 전달"<<endl;
        return false;
    }
 
    x=xpos;
    return true;
}    
cs



Rectangle 클래스의 정보 은닉

1
2
3
4
5
6
7
8
9
10
class Rectangle
{
private:
    Point upLeft;
    Point lowRight;
 
public:
    bool InitMembers(const Point &ul, const Point &lr);
    void ShowRecInfo() const;
};
cs



1
2
3
4
5
6
7
8
9
10
11
bool Rectangle::InitMembers(const Point &ul, const Point &lr)
{
    if(ul.GetX()>lr.GetX() || ul.GetY()>lr.GetY())
    {
        cout<<"잘못된 위치정보 전달"<<endl;
        return false;
    }
    upLeft=ul;
    lowRight=lr;
    return true;
}
cs

3-7 행 : 좌 상단과 우 하단이 바뀌는 것을 막는다. (우 하단의 좌표값이 더 작은것은 말이 안되므로)



const 함수


멤버 함수의 const 선언

: 동일 클래스에 선언된 멤버 변수의 값을 변경하지 못하도록 선언

1
2
3
4
// const함수내에서는 동일 클래스에 선언된 멤버 변수의 값을 변경하지 못함
int GetX() const;
int GetY() const;
void ShowRecInfo() const;
cs



다음과 같은 경우는 주의!

const 함수내에서는 const 선언되지 않은 함수를 호출하지 못함


다음과 같은 함수 호출은 컴파일 에러를 일으킨다. 

GetNum함수가 값을 변경할 수 있는 가능성이 내포되어 있기 때문이며 이를 해결하려면 GetNum함수에 const선언을 추가해야 한다.

1
2
3
4
5
6
7
8
9
// 멤버 함수 GetNum, ShowNum
int GetNum()
{
    return num;
}
void ShowNum() const
{
    cout<<GetNum()<<endl;    // 컴파일 에러
}
cs

const로 상수화된 객체를 대상으로도 const 멤버함수만 호출 가능. 역시 이를 해결하려면 GetNum함수에 const선언을 추가해야 함. 
1
2
3
4
5
// GetNum이 const 선언되지 않았다고 가정
void InitNum(const EasyClass &easy)
{
    num=easy.GetNum();    // 컴파일 에러 
}
cs



캡슐화 (Encapsulation)
: 관련있는 모든 것들을 하나의 클래스 안에 묶는 것

아래의 class들은 감기알약에 대해 나름의 캡슐화를 한 것이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class SinivelCap    // 콧물 처치용 캡슐
{
public
    void Take() const {cout<<"콧물이 싹~ 납니다."<<endl;}
};
 
class SneezeCap    // 재채기 처치용 캡슐
{
public
    void Take() const {cout<<"재채기가 멎습니다."<<endl;}
};
 
class SnuffleCap   // 코막힘 처치용 캡슐
{
public
    void Take() const {cout<<"코가 뻥 뚫립니다."<<endl;}
};
 
cs

하지만 다음과 같은 조건이라면 이는 캡슐화가 제대로 되지 않은 것이다.
 1. 코 감기가 하나의 증상이 아닌 여러 증상을 동반한다.
 2. 복용에 대한 순서나 방법이 정해져있다.

따라서 이 경우 제대로 된 캡슐화가 필요하며, 다음과 같이 관련 클래스를 하나로 묶을 필요성이 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class CONTAC600 
{
private:
    SinivelCap sin;
    SneezeCap sne;
    SnuffleCap snu;
 
public:
    void Take() const
    {
        sin.Take();
        sne.Take();
        snu.Take();
    }
};
cs

4-6행 : 코 감기와 관련된 캡슐을 하나로 묶음
9행 : 약의 복용 순서를 정의


1
2
3
4
5
class ColdPatient
{
public:
    void TakeCONTAC600(const CONTAC600 &cap) const { cap.Take(); }
};
cs

위의 ColdPatient 클래스는 CONTAC600 클래스의 내용이 수정 및 추가되라도 바뀔 필요가 없다.


 캡슐화 관련 예제 

#include <iostream>
using namespace std;

class SinivelCap    // 콧물 처치용 캡슐
{
public:
	void Take() const { cout << "콧물이 싹~ 납니다." << endl; }
};

class SneezeCap    // 재채기 처치용 캡슐
{
public:
	void Take() const { cout << "재채기가 멎습니다." << endl; }
};

class SnuffleCap   // 코막힘 처치용 캡슐
{
public:
	void Take() const { cout << "코가 뻥 뚫립니다." << endl; }
};

class CONTAC600
{
private:
	SinivelCap sin;
	SneezeCap sne;
	SnuffleCap snu;

public:
	void Take() const
	{
		sin.Take();
		sne.Take();
		snu.Take();
	}
};

class ColdPatient
{
public:
	void TakeCONTAC600(const CONTAC600 &cap) const
	{
		cap.Take();
	}
};

int main(void)
{
	CONTAC600 cap;
	ColdPatient sufferer;
	sufferer.TakeCONTAC600(cap);
	return 0;
}


Output:

1
2
3
콧물이 싹~ 납니다.
재채기가 멎습니다.
코가 뻥 뚫립니다.


해당 함수가 속한 객체의 멤버를 변경할 수 없도록 const 함수



캡슐화의 이점

: A 클래스가 잘 캡슐화 되었다면, 이 A클래스가 변경되더라도,

A와 연관된 다른 클래스는 변경될 필요가 없거나 변경 범위가 최소화된다는 것이다.


728x90