C++의 핵심, 클래스

이번 강의에서는 C에서 C++로 확장하는 진정한 핵심인 클래스(Class)에 대해서 알아보려고 해요. 더불어 클래스를 통해 가능해진 객체 지향 프로그래밍(Object Oriented Programming)이 무엇인지도 알아보지요.



강의들은 모두 무료입니다. 단, 저작권은 키클 코딩랩 에 있으며, 무단 복제 및 배포를 엄금합니다.
이를 어길 시, 본 사이트의 서버가 미국에 있으므로, 미국법에 의해 처벌될 수도 있습니다.




객체 지향 프로그래밍 (OOP)

이전 강의 C++에서의 구조체에서는, C 언어에서 C++로의 확장을 가능하게 하는 출발점인 "구조체(Structure) 안에 함수 구현하기"를 공부했었지요. 그리고, 구조체 안에 함수를 구현함으로써, 속성 뿐만아니라 기능까지 모두 갖춘 "온전한 개체"를 구현할 수 있다고 했었지요. 그리고, 개체의 예로 "사람(Person)"을 들어서 설명했었는데요. 사실, "온전한 개체"를 코딩하기 위해서는 한가지 더 생각해야할 것이 있답니다.
사람의 속성이나 기능에는 "나이"와 "이름"등과 같이 외부에 공개하는 것들이 있기도 하지만, "의료기록"이나 "은행계좌 비밀번호" 등 외부에 공개하면 안되는 것과 "남들보다 잘 나오는 방귀"나 "유난히 소리가 큰 코골이" 등 경우에 따라서는 숨기고 싶은 기능들도 있지요. 즉, "온전한 개체"로서 "사람"을 코딩하고자 하면, 일부 속성이나 기능에 대해서 외부의 접근을 금지할 수도 있어야 하는 것이랍니다.

C++에서 추가된 클래스(Class)는 구조체(Structure)의 기법을 모두 포함하면서, 동시에 속성이나 기능에 대한 외부의 접근 범위를 설정할 수 있게 하여 진정으로 "온전한 개체"를 구현하게 해준답니다. 이러한 클래스의 특성을 활용하여, 온전한 개체들 중심으로 코딩을 하여 프로그램을 개발하는 것을 객체 지향 프로그래밍(OOP, Object Oriented Programming)이라고 한답니다. 참고로, 저는 "객체"라는 표현이 자칫 기능은 없고 속성만 있는 "물체"의 의미로 느껴질까봐, "개체"라는 표현을 많이 사용했는데요. 실제로는, "객체"가 공식적으로 사용되는 표현이랍니다.





클래스(Class)란?

위에서 말했듯, C++의 클래스(Class)는 구조체(Structure)의 기법을 모두 포함함과 동시에, 속성이나 기능에 대한 외부의 접근 범위를 설정함으로써 "온전한 개체"의 구현을 가능하게 하지요. 그리고, 이것은 우리가 객체 지향 프로그래밍(OOP)를 할 수 있도록 도와 준답니다.
그렇다면, 클래스에 대하여 자세히 알아볼까요?

[문법] 클래스 (Class)

위에서 보듯이, 사실 클래스는 몇 가지를 제외하고는 구조체와 거의 동일한 코딩 기법이라는 것을 알 수 있어요. 클래스의 코딩 방법에서 접근 지정자(Access Specifier)에 대해서 언급했는데요, 이것에 대해서 조금 더 알아보지요.

[문법] 접근 지정자 (Access Specifier)

위에서, protected 접근 지정자는 상속(Inheritance)과 관련되어 있는데요. 클래스의 상속은 나중에 공부할 것이니, 일단 넘어가기 바랍니다.





클래스 코딩하고 실행하기

그럼, 이제 직접 클래스를 코딩해 보면서 공부한 내용을 확인해 볼까요?
원하는 폴더/디렉토리를 만들고 gedit 문서 편집기를 이용하여 "lec16_class.cpp"라는 이름의 C++ 파일을 만들어 볼게요. C++로의 확장을 공부할 것이기 때문에, 확장자가 "cpp"인 C++ 파일을 만든 것이랍니다. 그리고, 아래처럼 강의 C++에서의 구조체에서 코딩한 내용을 복사해서 붙여 넣어 볼게요. 그리고, 아래 코드들이 어떤 의미를 갖는지 잊어버렸다면, 꼭 복습하고 오세요. 클래스의 구현과 관련없는 코드는 설명을 생략할거랍니다.

lec16_class.cpp
#include <cstdio> // #include <stdio.h>

struct Person {
	char *name;
	int age;
	
	int introduce() {
		printf("My name is %s.\n", name);
		return age;
	}
};

int main () {
	Person prs0;
	struct Person prs1;

	prs0.name = "Heungbu";
	prs0.age = 47;	
	prs1.name = "Nolbu";
	prs1.age = 54;

	printf("I'm %d years old\n", prs0.introduce());
	printf("I'm %d years old\n", prs1.introduce());
}

이제, 위에서 구조체로 구현했던 "Person"을 클래스로 구현해 볼까요?
가장 먼저 해야할 일은, 바로 "struct"를 "class"로 바꿔야 하는 것이겠죠? 아래 줄3과 줄15에서 "struct"를 "class"로 바꾸었답니다. 줄14와 줄15을 보면, 클래스 "Person"을 새로운 데이터타입으로 간주하면서 변수 prs0와 prs1를 선언했는데요. 클래스 변수를 선언할 때, 구조체 변수 선언과 마찬가지로 "class" 키워드를 사용해도 되고 안해도 된다는 것을 알 수 있지요.
놀랍겠지만, 이것으로 우리는 클래스 "Person"을 성공적으로 구현한 것이랍니다!
접근 지정자를 명시적으로 코딩은 안 했지만, 이런 경우 멤버들은 모두 private 접근 권한을 얻게 된다고 했었죠? 그래서, 줄3~줄11처럼 클래스 "Person"을 구현함에 있어 문제될 것은 아무것도 없답니다.
하지만!! 아래의 cpp 파일은 줄17~줄23의 코드들 때문에, 컴파일하면 에러 메세지를 만나게 되요.
이유가 무엇일까요? 바로, "Person" 클래스의 멤버들인, name, age, introduce()는 모두 private의 접근 권한을 갖게 되어 외부에서 접근할 수 없는데, 줄17~줄23은 모두 외부에서 각각의 멤버들에 접근하는 코드들이기 때문이지요.

lec16_class.cpp
#include <cstdio> // #include <stdio.h>

class Person {
	char *name;
	int age;
	
	int introduce() {
		printf("My name is %s.\n", name);
		return age;
	}
};

int main () {
	Person prs0;
	class Person prs1;

	prs0.name = "Heungbu";
	prs0.age = 47;	
	prs1.name = "Nolbu";
	prs1.age = 54;

	printf("I'm %d years old\n", prs0.introduce());
	printf("I'm %d years old\n", prs1.introduce());
}

그럼, 컴파일할 때 에러 메세지를 만나지 않도록, 접근 권한을 고려하여 위의 코드들을 수정해 볼까요?
일단, 이름(name)과 나이(age)는 계속 private으로 외부의 접근을 차단해 두는 것으로 하지요. 하지만, 소개하는 기능은 외부와의 소통을 의미하니, introduec() 멤버 함수는 외부에서 접근이 가능하도록 아래 줄7처럼 public 접근 지정자를 삽입할게요. 그리고, name과 age 접근 권한에 따른 컴파일 에러를 막기 위해서, 위의 줄17~줄20의 코드는 삭제하여 아래처럼 name과 age에 직접적으로 접근하는 코드가 없도록 하지요.

lec16_class.cpp
#include <cstdio> // #include <stdio.h>

class Person {
	char *name;
	int age;
	
public:
	int introduce() {
		printf("My name is %s.\n", name);
		return age;
	}
};

int main () {
	Person prs0;
	class Person prs1;

	printf("I'm %d years old\n", prs0.introduce());
	printf("I'm %d years old\n", prs1.introduce());
}

하지만, "흥부"와 "놀부"의 이름과 나이를 받아서 저장하는 기능은 필요하니, 아래 줄13~줄17처럼 "Person" 클래스에 setNameAge()라는 멤버 함수를 public 접근 권한으로 추가해 보지요. 이 멤버 함수는 문자열인 이름과 정수값인 나이가 전달인자 name_in과 age_in을 통해 들어올 경우, private 접근 권한을 갖는 name과 age 멤버 변수(member variable)에 접근하여 저장하는 기능을 하고 있답니다. 이처럼, 클래스 안의 다른 멤버들이 private인 멤버들에 접근 하는 것은 가능하다는 점 유념하세요. 아래 줄16에서는 그저 의미없는 정수값 1을 리턴하고 있는 것이니 크게 신경쓰지 않아도 됩니다.

lec16_class.cpp
#include <cstdio> // #include <stdio.h>

class Person {
	char *name;
	int age;
	
public:
	int introduce() {
		printf("My name is %s.\n", name);
		return age;
	}
	
	int setNameAge(char *name_in, int age_in) {
		name = name_in;
		age = age_in;
		return 1;	
	}
};

int main () {
	Person prs0;
	class Person prs1;

	prs0.setNameAge("Heungbu", 47);	
	prs1.setNameAge("Nolbu", 54);

	printf("I'm %d years old\n", prs0.introduce());
	printf("I'm %d years old\n", prs1.introduce());
}

줄24~줄25에서는, 멤버 함수 setNameAge()를 통해서 "흥부"와 "놀부"의 이름과 나이를 각각 Person 클래스 변수 prs0와 prs1에 저장하고 있답니다. 앞서 언급한 대로, 멤버 함수 setNameAge()는 의미없는 값 1을 리턴하고 있기 때문에, 리턴값을 따로 정수형 변수를 만들어 받지는 않았답니다.
이로써, "사람"이라는 개체를 구현하는 "Person" 클래스를 중심으로 한 객체 지향 프로그래밍(OOP)을 마무리해 볼게요.

이제, 파일을 저장하고 gedit 편집기 닫기를 하세요.
그리고, 아래 줄1처럼 컴파일하면, 줄2~줄8과 같은 경고(Warning) 메세지를 볼지도 몰라요. 이 경고는 문자열을 다룰때 C++는 문자형 포인터(char *)를 사용하지 않기를 바란다는 의미로, 나중에 자세히 공부할 기회가 있을 거예요. 여하튼, 이 문구는 경고일 뿐이지, 문법(Syntax) 에러(Error)는 아니랍니다. 고로, 실행하는데 아무 문제가 없다는 것이죠. 줄9처럼 실행해 보면, 각각 흥부와 놀부의 이름과 나이가 순서대로 출력되는 것을 볼 수 있답니다.

.../my_folder$ gcc lec16_class.cpp
lec16_class.cpp: In function ‘int main()’:
lec16_class.cpp:24:31: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
  prs0.setNameAge("Heungbu", 47); 
                               ^
lec16_class.cpp:25:29: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
  prs1.setNameAge("Nolbu", 54);
                             ^
.../my_folder$ ./a.out
My name is Heungbu.
I'm 47 years old
My name is Nolbu.
I'm 54 years old
.../my_folder$




구조체와 클래스

클래스를 코딩해 보고 실행해 보니 이해가 잘 되었나요?
이전 강의 C++에서의 구조체에서 구현했던 구조체 "Person"을 클래스로 바꾸는 과정에서 우리가 했던 것의 핵심은, "struct"를 "class"로 바꾸고 접근 지정자(Access Specifier)를 적절한 위치에 코딩한 것이었지요.
이 시점에서 놀라운 점 하나 알려드릴게요. 바로, 구조체도 사실은 클래스처럼 접근 지정자를 가질 수 있고 클래스와 같은 방식으로 코딩할 수 있다는 것입니다.
그렇다면, 키워드 "struct"와 "class"의 차이 말고, 도대체 구조체와 클래스는 무엇이 다르냐? 차이점은 단 하나, 접근 지정자가 명시적으로 코딩되지 않았을 때 클래스의 멤버들은 private의 접근 권한을 갖는 반면에, 구조체는 public을 갖는다는 것이랍니다. 이러한 이유로, 강의 C++에서의 구조체에서는 구조체의 name과 age에 마음대로 접근할 수 있었던 것이지요.
이렇듯, C++에서 구조체와 클래스는 사실 큰 차이가 없답니다. 단지, 클래스의 멤버들에 대한 디폴트(default) 접근 권한을 private으로 정함으로써, "'사람'과 같이 '온전한 개체'들은 대개 '숨기고 싶은 정보'를 갖고 있다"는 주지의 사실을 클래스가 가장 잘 반영하게 만든 것이 아닐까 생각해 봅니다.


강의에서 작성된 소스 코드 (source code)를 다운받으려면, 다음 링크를 클릭하세요: lec16_class.cpp

혹시, 이해가 잘 안되는 부분에 대한 질문이 있거나 다루어 줬으면 하는 주제가 있으면, 화면 오른쪽 하단에 "질문하기" 버튼을 이용해 주세요.






발자취

2019-09-11 "키클 코딩랩 - 미국 공학박사 아빠의 코딩 연구소"로 이름 변경
2019-06-28 코딩 교실 공개
2019-03-18 코딩 교실 제작 시작

바로가기
Python 배움터
C/C++ 배움터
About
Contact
Privacy Policy
강의목록
질문하기
처음으로