프로그램을을 사용하는 사용자가 알아야 하는 것은 프로그램 사용법이지 프로그램의 내부 동작이나 상세 구조가 아니다. 사용자가 굳이 알 필요가 없는 불필요한 정보는 숨김으로써 사용자는 최소한의 정보만으로 프로그램을 쉽게 사용할 수 있어야 한다.
C++에서는 클래스의 정보 은폐 기능을 지원하기 위해 private, public, protected 등의 접근제어 키워드를 통해 선언된 클래스 외부에서 직접적인 접근을 허용하지 않는것을 정보은닉이라 할 수 있다.
하지만 간접적 접근 경로를 제공해줘야 한다. 숨길 멤버와 공개할 멤버의 블록을 구성하도록 해서, 공개된 멤버는 외부에서 자유롭게 읽을 수 있지만 숨겨진 멤버를 참조하려고 시도하면 컴파일 과정에서 접근할 수 없다는 에러로 처리를 하면 된다. (아래는 정보은닉의 예)
- #include<iostream>
- using namespace std;
- class Point
- {
- int x; // x좌표의 범위 : 0 ~ 100
- int y; // y좌표의 점위 : 0 ~ 100
- public:
- int GetX(){ return x; }
- int GetY(){ return y; }
- void SetX(int _x){ x=_x; }
- void SetY(int _y){ y=_y; }
- };
- int main()
- {
- int x, y;
- cout<<"좌표입력 : ";
- cin>>x>>y;
- Point p;
- p.SetX(x);
- p.SetY(y);
- cout<<"입력 된 데이터를 이용해서 그림을 그림"<<endl;
- return 0;
- }
캡슐화를 함으로써 정보 은닉도 함께 가져오는 효과를 가져오기도 한다. 아래의 캡슐화가 된 예제와 캡슐화가 안된 예제를 한번 보시죠.
3-1) 캡슐화가 안된 예제
- #include<iostream>
- using namespace std;
- class Point
- {
- int x; // x좌표의 범위 : 0 ~ 100
- int y; // y좌표의 범위 : 0 ~ 100
- public:
- int GetX(){ return x; }
- int GetY(){ return y; }
- void SetX(int _x);
- void SetY(int _y);
- };
- void Point::SetX(int _x)
- {
- if(_x<0 || _x>100) {
- cout<<"X좌표 입력 오류, 확인 요망"<<endl;
- return;
- }
- x=_x;
- }
- void Point::SetY(int _y)
- {
- if(_y<0 || _y>100)
- {
- cout<<"Y좌표 입력 오류, 확인 요망"<<endl;
- return;
- }
- y=_y;
- }
- class PointShow
- {
- public:
- void ShowData(Point p)
- {
- cout<<"x좌표: "<<p.GetX()<<endl;
- cout<<"y좌표: "<<p.GetY()<<endl;
- }
- };
- int main()
- {
- int x, y;
- cout<<"좌표입력 : ";
- cin>>x>>y;
- Point p;
- p.SetX(x);
- p.SetY(y);
- PointShow show;
- show.ShowData(p);
- return 0;
- }
예를 들어 클래스를 정의하고 나서 프로젝트가 진행된 상황에서 문제를 발견, 포인트 클래스에다가 자기가 지니고 있는 변수 x,y에 대해 출력하는 기능을 넣어 줘야 되겠구나 생각을 하게 된다고 가정을 해봅시다. 하지만 이미 point라는 클래스는 이미 정해져 있고, 프로젝트가 이미 진행이 되어 있기 때문에, 기존의 클래스를 변경하는 것은 어려운 일 일것이다.
그래서 일반적으로 출력이란 기능이 없으므로, 이에 대한 기능을 클래스로 정의 하기에 이를 것입니다. 포인트 클래스의 객체를 인자로 받아서 리턴되는 데이터를 출력하는 형태로 클래스를 정의하는 pointshow 라는 클래스를 만들게 되는 것이죠.
메인함수에서 포인트 객체도 생성하고, 출력을 위해 show라는 객체도 생성하게 되고, 결과는 무리 없이 출력 되겠지만, 이것은 캡슐화가 무너졌다 라고 볼 수 있습니다.
showdata라는 함수는 내가 정의한 포인트 함수의 x,y를 출력하기 위한 함수 이므로, 이것은 포인트에 대한 기능을 가진 것이라고 볼 수 있으므로 showdata라는 함수는 포인트 클래스 안에 존재 하는것이 맞는 것이죠.
3-2) 캡슐화된 예제 : 위 상황에서 캡슐화가 제대로 됐다고 하면, 아래와 같은 예제가 나올 것입니다.
- #include<iostream>
- using namespace std;
- class Point
- {
- int x; // x좌표의 범위 : 0~100
- int y; // y좌표의 범위 : 0~100
- public:
- int GetX(){ return x; }
- int GetY(){ return y; }
- void SetX(int _x);
- void SetY(int _y);
- void ShowData(); //캡슐화를 위해 추가된 함수.
- };
- void Point::SetX(int _x)
- {
- if(_x<0 || _x>100) {
- cout<<"X좌표 입력 오류, 확인 요망"<<endl;
- return;
- }
- x=_x;
- }
- void Point::SetY(int _y)
- {
- if(_y<0 || _y>100)
- {
- cout<<"Y좌표 입력 오류, 확인 요망"<<endl;
- return;
- }
- y=_y;
- }
- void Point::ShowData()
- {
- cout<<"x좌표: "<<x<<endl;
- cout<<"y좌표: "<<y<<endl;
- }
- int main()
- {
- int x, y;
- cout<<"좌표입력 : ";
- cin>>x>>y;
- Point p;
- p.SetX(x);
- p.SetY(y);
- p.ShowData();
- return 0;
- }
코드의 재활용성을 높이고 에러발생을 최소화하며 다이나믹한 속성을 높이기 위해서 캡슐화가 필요 하다.
댓글 없음:
댓글 쓰기