2주차(4) - 데이터 구조를 공부하기 위한 C++의 Class의 기본개념
C++ 언어는 일반 C언어와 달리 Class라는 개념을 지원하는 데 Class에 대해서 알아보기 전에 먼저 Structure의 개념에 대해서 먼저 알아보는 것으로 하겠다.
Structures
여러 종류의 Data Type을 하나로 묶어놓은 것 (Compound Data Type)
실제로 우리가 사용하는 수많은 정보 시스템들은 그 내부의 근간이 데이터 베이스(DB)를 유지하고 있다. 즉, 실세계에서 존재하는 데이터들을 잘 저장해놓고 필요에 따라 이를 조회해서 보여줄 수 있는 시스템을 구상할 때 이에 대한 가장 기본적인 배경이 되는 것이 바로 Structure Type 이다. 즉, 우리가 어떤 프로그램으로 표현하고자 하는 대상물을 하나의 분류로 정해놓고 그 분류가 갖는 속성을 표현하는 것을 Structure Type을 통해서 수행할 수 있다.
만약 다음과 같이 구성된 학생에 대한 정보를
1. 학번
2. 이름
3. 연락처
구조체로 표현한다면 아래와 같이 표현할 수 있다.
struct StudentData {
int student_id;
char name[20];
char phone[20];
}s1, s2;
이는 C언어에서 사용하던 표현을 통해서 사용하던 방식을 그대로 가져온 것이고, 위에서 볼 수 있듯이 C언어에서의 Structure Type은 Structure의 구조정의 부분과 변수선언 부분을 한 문장으로 구성한다는 점이다.
그런데 C++에서는 이를 별도로 고려할 수 있으며 Structure Tag를 마치 Type name처럼 사용할 수 있다는 것이다. 그래서 위와 같이 선언되어 있는 구조체에 대해서 구조체 변수를 추가적으로 더 선언하고 싶은 경우 아래와 같이 Structure Tag를 Type name처럼 사용하여 정의하는 것이 가능하다. 물론 C언어에서도 Typedef을 적절히 사용하면 이렇게 사용할 수 있도록 구성할 수 있지만 C++에서는 이러한 과정없이 자체적으로 지원한다는 점에서 차이점이 있다.
// StudentData 구조체 변수를 별도로 선언하는 경우
struct StudentData s3, s4; // C언어에서의 방식
StudentData s3, s4; // C++는 바로 이렇게 선언할 수 있다.
그래서 C++에서 Structure의 특징을 다음 두 가지로 정리해볼 수 있다.
1. C언어의 Tag 표현을 'type name'처럼 사용
2. Member Data 뿐만 아니라 member function도 정의할 수 있음.
1. C언어의 Tag 표현을 "type name"처럼 사용
struct keyword 없이 추가 변수를 정의할 수 있다. (User Define Type)
C++는 기존 C언어의 특징을 모두 수용하기 때문에 struct를 사용한 형식도 사용가능 하다.
2. Member Data 뿐만 아니라 member function도 정의할 수 있음
사실상 C++에서는 Class의 개념과 유사하다고 볼 수 있다. 단, 뒤에서 다룰 내용이지만 Structure에서 정의하는 member function의 경우 member access control의 default가 public이라는 점을 기억해야 한다. 하지만 이러한 개념이 필요할 경우 Structure를 사용하기보다는 Class를 사용하게 되기 때문에 많이 접하지는 않을 것이다.
Class
class는 기본적으로 아래와 같은 특징을 가진다.
1. OOP의 기본
2. Member data와 Member function으로 구성
3. Member access specifier 개념 지원
1. OOP의 기본
OOP는 객체지향 프로그래밍(= Object Oriented Programming)을 의미하는 용어로서 Class는 Object를 표현하기 위한 Data Type에 해당한다.
2. Member data와 Member Function으로 구성
Class는 Member data와 Member Function으로 구성되는 데 이는 어떤 대상물(Object)이 가지는 Data 적인 속성 뿐만 아니라 그것이 동작하는 기능에 대한 속성까지 포함함을 의미한다. 그래서 이를 다른 표현으로 Class는 Attributes(data members), Behaviors(data functions)를 모두 포함하는 개념이라고 표현하기도 한다. 그래서 이전에 살펴본 ADT와 연관지어서 가장 전형적으로 포함되는 방식이 Class라고 할 수 있다.
3. Member Access Specifier의 개념지원
Class는 각 member들은 외부에서 접근이 가능 여부에 따라서 아래와 같이 구분할 수 있다.
1. public - class 외부에서도 access 가능함을 의미
2. private - member 또는 friend function에서만 access가 가능함을 의미 - default access mode!
3. protect - inheritance가 가능한 private 속성
위와 같은 종류의 Member Access Specifier를 사용함으로서 Class가 가지는 각 member들에 대한 접근 정도를 설정해줄 수 있다. 이는 모두 OOP의 개념을 위해서 추가된 개념이라고 볼 수 있다.
OOP의 기본원칙
1. Information Hiding
2. Data Abstraction
3. Encapsulation
1. Information Hiding
Class가 가지는 어떤 연산(Member Function)이 구체적으로 어떻게 동작하는 지에 대한 자세한 내용은 사용자에게 알리지 않고 숨기는 것을 말한다. 해당 정보는 사용자가 알지 못해도 사용할 수 있기 때문이다.
2. Data Abstraction
Data가 ADT/Class 내에서 구체적으로 어떻게 다뤄지는 지를 사용자에게 알리지 않는 것을 말한다. 위의 Information Hiding과 마찬가지로 해당 정보는 사용자가 알지 못해서 Data Type을 사용함에 있어서 전혀 문제가 없기 때문이다.
3. Encapsulation
Data와 이와 관련된 연산(Operation)을 하나로 묶어서 생각하되, 이와 관련된 세부적인 내용은 숨기는 것을 말한다.
그래서 위와 같은 OOP의 기본원칙들을 C언어가 반영할 수 있도록 하여 탄생한 것이 C++ 언어라고 할 수 있다.
그렇다면 이제 C++언어를 통해서 어떻게 Class를 정의하고 이를 사용할 수 있는 지에 대해서 알아보도록 하겠다. 아래와 같은 데이터를 프로그램에서 다루기 위한 Class를 정의하고 이를 사용하는 상황을 가정해보자. 이를 위한 예시코드는 아래와 같다.
이름 | 학번 | 전공 |
라이언 | 21700000 | 컴퓨터 공학 (1) |
춘식 | 22000000 | 디자인 (2) |
죠르디 | 21900000 | 생명공학 (3) |
class Student {
private:
char sName[20];
int sId;
public:
int major;
void setId(int n); // sId 값을 설정하는 연산
int getId(); // sId 값을 불러오는 연산
}
위에서 주목할 점은 Class를 선언 시에는 "Class"라는 Keyword를 사용한다는 점과 그 뒤에 Class name이 온다는 점과, private, public의 영역을 구분하여 사용한다는 점이다. 이전에 살펴본 것처럼 private로 설정된 sName, sId member는 class 외부에서 접근할 수 없고, 나머지 public으로 정의된 major, setId(), getId()의 경우 모두 class 외부에서도 접근이 가능하다.
int main()
{
Student s1; // Object 생성
s1.setId(22100000);
s1.major = 1;
cout << s1.getId() << endl;
return 0;
}
그런데 위의 Class의 정의를 보면 member sId 값을 설정하고 불러오는 setId(), getId() Function이 존재하는 것을 확인할 수 있는 데 해당 Function에 대한 정의는 따로 보이지 않고 그냥 선언만 되어있는 형식이다. 실제로 이들은 일반적인 Function의 정의처럼 Class member Function들의 구체적인 동작이 Class의 정의에 별도로 기술되지 않고 별도로 분리되어 있는 이유 또한 이전에 살펴본 Abstraction의 개념을 위한 것이다.
그런데 일반적인 function의 정의와 class의 member function을 정의함에 있어서는 약간 문법적인 차이가 존재한다. 그렇기 때문에 이에 대해서 알아두고 일반적인 function의 정의와 class member function의 정의를 구분해야할 필요성이 있다.
:: Scope Resolution Operator
class의 member function을 정의할 때에는 '::' 기호를 사용하게 되는 데 해당 기호를 "Scope Resolution Operator"라고 부르며 이는 "~~란 이름의 클래스에 속한" 이라는 의미를 가진 연산자 이다. 그래서 class member function을 정의할 때에는 아래와 같은 형식으로 정의하게 된다.
(Return Type) (Class name) :: (member function name) (parameter...)
// member function 구현 내용
void Student:: setId(int n)
{
sId = n;
}
int Student:: getId()
{
return sId;
}
그래서 위와 같이 class의 member function을 정의하여 object를 선언하여 편리하게 사용할 수 있게 된다.
C++언어의 Class에 대해서 이 정도의 내용을 알아두고 연습하면 자신이 원하는 형태의 데이터 구조를 class로 정의하고 활용하는 것이 가능할 것이다.
stack을 Class로 정의하기
그래서 이전에 살펴보았던 Stack을 Class를 사용하여 아래와 같이 정의할 수 있겠다.
(여기서 SIZE의 경우 사전에 정의된 상수임을 가정함.)
class myStack {
private:
int s[SIZE];
int top;
public:
void init();
void push(int x);
int pop();
bool stack_full();
bool stack_empty();
}
void myStack:: init()
{
top = 0;
}
void myStack:: push(int x)
{
s[top] = x;
top++;
}
int myStack:: pop()
{
top--;
return s[top];
}
bool myStack:: stack_full()
{
if(top>=SIZE)
return true;
else
return else;
}
bool myStack:: stack_empty()
{
if(top == 0)
return true;
else
return false;
}
그리고 이 정의들을 바탕으로 아래와 같은 프로그램을 작성할 수 있다.
int main()
{
myStack s1;
int list[5] = {32, 123, 27, 131, 242};
int i, x;
s1.init();
for(int i=0 ; i<5 ; i++)
if(list[i] > 100)
s1.push(list[i]);
while(!stack_empty())
{
x = s1.pop();
cout << x << endl;
}
return 0;
}
'Computer Science > 자료구조' 카테고리의 다른 글
2주차(3) - ADT (0) | 2021.03.01 |
---|---|
2주차(2) - Stack(1) (0) | 2021.03.01 |
2주차(1) - 알고리즘의 성능분석 (0) | 2021.03.01 |
1주차(2) - 데이터 구조 학습을 위한 C++ 언어 기초 (0) | 2021.02.24 |
1주차(1) - 알고리즘과 데이터 구조 개요 (0) | 2021.02.24 |
댓글
이 글 공유하기
다른 글
-
2주차(3) - ADT
2주차(3) - ADT
2021.03.01 -
2주차(2) - Stack(1)
2주차(2) - Stack(1)
2021.03.01 -
2주차(1) - 알고리즘의 성능분석
2주차(1) - 알고리즘의 성능분석
2021.03.01 -
1주차(2) - 데이터 구조 학습을 위한 C++ 언어 기초
1주차(2) - 데이터 구조 학습을 위한 C++ 언어 기초
2021.02.24