이번에는 멤버의 가시성을 설정하는 접근 지정자에 관해 알아볼게요.
C언어의 구조체는 모든 곳에서 모든 멤버를 접근할 수 있어요. 이러한 특징은 개발자가 멤버에 접근하기 쉬워서 구현하기 쉽게 생각할 수 있지만 시나리오에 맞게 데이터를 유지하는 것은 어려울 수 있어요.
예를 들어 설명할게요.
프로그램에서 이름, 번호, 아이큐를 멤버로 갖는 학생 형식이 있다고 가정합시다.
학생 개체는 생성할 때 이름과 번호를 부여하고 아이큐는 100으로 설정하기로 해요. 그리고 학생이 공부하면 아이큐가 공부한 시간만큼 증가하게 만들거예요. 단 아이큐는 300을 넘지 않게 하기로 해요.
그런데 학생 개체를 사용하는 곳에서 학생 구조체의 멤버에 접근할 수 있어서 “공부하다.” 기능을 호출하지 않고 직접 아이큐를 조절하면 범위를 벗어날 수 있어요. 이와 같은 버그가 발생하였을 때 이를 발견하고 수정하는데 비용이 발생하겠죠.
//Student.h #pragma once #include <string.h> #include <stdio.h> #define MAX_NAME_LEN 20 #define DEF_IQ 100 //디폴트 IQ #define MAX_IQ 300 //최대 IQ typedef struct Student Student; struct Student { int num; char name[MAX_NAME_LEN]; int iq; }; void Student_Student(Student *stu,int num, const char *name); //생성자 void Student_Study(Student *stu, int hours);//공부하다. void Student_View(Student *stu);//학생 정보 출력
//Student.c #include "Student.h" void Student_Student(Student *stu,int num, const char *name) { stu->num = num; strcpy_s(stu->name,MAX_NAME_LEN,name); stu->iq = DEF_IQ; } void Student_Study(Student *stu, int hours) { printf("%s 학생 %d시간 공부하다.\n",stu->name, hours); if( stu->iq + hours >MAX_IQ) { stu->iq = MAX_IQ; } else { stu->iq += hours; } } void Student_View(Student *stu) { printf("번호:%d, 이름:%s, 아이큐:%d\n",stu->num,stu->name,stu->iq); }
//Program.c #include "Student.h" int main() { Student stu; Student_Student(&stu,34,"홍길동"); Student_View(&stu); Student_Study(&stu,50); Student_View(&stu); stu.iq += 300; //멤버에 직접 접근하여 값을 설정 Student_View(&stu); return 0; }
▷실행 결과
번호:34, 이름:홍길동, 아이큐:100 홍길동 학생 50시간 공부하다. 번호:34, 이름:홍길동, 아이큐:150 번호:34, 이름:홍길동, 아이큐:450
위 예제에서 main 함수에서 직접 학생의 멤버 iq에 접근하여 설정하지 않고 Student_Study 함수를 사용했다면 학생의 IQ는 최대값을 넘지 않아요. 결국 C언어에서는 어디에서나 구조체의 멤버에 접근할 수 있어서 발생한 버그예요.
C++언어에서는 멤버의 가시성을 설정하는 접근 지정자 문법을 제공하고 있어요.
class 정의할 때 private, protected, public 키워드와 콜론(:)을 지정하여 이 후의 작성한 멤버의 가시성을 설정할 수 있어요.
private 접근 지정은 형식 내부에서만 접근할 수 있습니다.
public은 모든 곳에서 멤버에 접근할 수 있습니다.
protected는 파생 형식에서도 접근할 수 있습니다. 이 부분은 상속을 다루면서 설명하기로 해요.
클래스는 디폴트 가시성이 private이고 구조체는 public입니다.
class Student { int num; string name; int iq; public: Student(int _num,string _name); void Study(int hour); void View(); };
클래스의 디폴트 접근 지정은 private입니다. 위처럼 정의하면 num과 name, iq는 디폴트로 접근 지정합니다.
그리고 public: 지정한 뒤에 세 개의 멤버는 접근 지정이 public입니다.
따라서 형식 외부에서 num, name, iq 멤버에 접근할 수 없어요.
다음의 코드는 C++언어에서 접근 지정을 통해 신뢰성을 강화한 코드입니다. 멤버 iq의 접근 지정을 디폴트인 private으로 설정하여 형식 외부에서 접근할 수 없게 만들었어요.
아직 멤버 메서드 캡슐화를 다루지 않은 상태여서 모두 이해할 수는 없지만 코드를 한 번 보시고 따라서 작성 및 분석해 보세요.
//Student.h #pragma once #include <string> using namespace std; #define DEF_IQ 100 //디폴트 IQ #define MAX_IQ 300 //최대 IQ class Student { int num; string name; int iq; public: Student(int _num,string _name); void Study(int hour); void View(); };
//Student.cpp #include "Student.h" #include <iostream> using namespace std; Student::Student(int _num,string _name) { num = _num; name = _name; iq = DEF_IQ; } void Student::Study(int hour) { cout<<name<<" 학생 "<<hour<<"시간 공부하다."<<endl; if (iq > MAX_IQ) { iq = MAX_IQ; } } void Student::View() { cout<<"번호:"<<num<<", 이름:"<<name<<", 아이큐:"<<iq<<endl; }
//Program.cpp #include "Student.h" int main() { Student stu(34,"홍길동"); stu.View(); stu.Study(50); stu.View(); //stu.iq += 300; //private 접근 지정한 멤버는 형식 외부에서 접근 못 함 stu.View(); return 0; }
▷실행 결과
번호:34, 이름:홍길동, 아이큐:100 홍길동 학생 50시간 공부하다. 번호:34, 이름:홍길동, 아이큐:150 번호:34, 이름:홍길동, 아이큐:150