티스토리 뷰
※ 주의 사항 ※
- 이 글의 목적은 '지식의 전달'이 아닌 '학습의 기록'입니다.
- 따라서 제가 이해하는 그대로의 내용이 포함됩니다.
- 따라서 이 글은 사실과는 다른 내용이 포함될 수 있습니다.
C++ 언어는 객체 지향 언어다. 객체 지향 언어가 무엇인지 절차 지향 언어와 비교해보면 이해가 빠르다. 근데 절차 지향 언어는 또 뭔데?? 절차 지향 프로그래밍이니 객체 지향 프로그래밍이니 하는 것은 프로그래밍의 패러다임을 얘기하는 것이다. 패러다임을 번역해보면 양식, 인식 체계라고 나오는데, 그냥 프로그램 코드를 짜는데 양식이 있다는 얘기다. 프로그래밍 언어 문법을 말하는 건가? 하는 생각이 들었다면 아직 잘못 이해하고 있는 것이다. 만약 C언어부터 공부하고 이제 C++를 배우고 있는 입장이라면 코드를 짜는 데에도 양식이 있었어? 하는 생각이 들 수 있다. 프로그래밍의 패러다임에 대해 이해시키려면 조금 긴 얘기를 해야 하니 인내심을 가지고 천천히 봐주길 바란다.
절차 지향 프로그래밍이란?
C언어를 배웠다면 C언어는 저수준 언어라는 것을 알 것이다. python 같은 프로그래밍 언어는 고수준 언어다. 그런데 C언어보다도 더 저수준의 언어에는 무엇이 있는지 아는가? 어셈블리어가 그중 하나이다. 어셈블리어가 뭔지는 설명하지 않는다. 그냥 C언어보다도 더 해 먹기 어려운 언어겠구나 하고 넘어가면 된다. 어셈블리어는 명령형 프로그래밍 언어다. 명령형 프로그래밍이란 컴퓨터가 수행할 명령들을 단순히 순서대로 나열해놓는 프로그래밍 패러다임이다. 아래는 어셈블리어의 코드다.
이 코드가 어떻게 동작하는지는 나도 모른다 아무튼 중요한 건 그게 아니다. *표시된 줄은 아마도 주석 처리되는 것 같지만 아닐 수도 있다. 아무튼 다시 얘기하지만 내가 위의 어셈블리 코드를 잘못 읽는 것은 하나도 중요하지 않다. 중요한 건 위 어셈블리 코드가 정말 밋밋하게 쭉 나열되어 있다는 것이다. 컴퓨터는 위 코드의 가장 윗부분부터 아래로 하나씩 읽어 내려갈 것이다. 그리고 끝에 다다르면 프로그램의 실행도 멈출 것이다.
그런데 정말로 위에서 아래로 한 번 훑고 말 코드라면 이걸 읽고 동작하는 것은 컴퓨터라고 할 수 있을까? 그 컴퓨터는 코드가 다시 작성되지 않는 한 매번 똑같은 동작만 수행할 것이다. 컴퓨터란 코드를 새로 작성하지 않아도 처리하는 변수나 조건에 따라 실행 결과가 다르게 나올 수 있어야 하는 게 당연하지 않나. 이를 가능하게 해주는 게 JMP라는 키워드(?)다.
JMP는 jump를 의미하는데 프로그램 실행 중에 JMP를 만나면 JMP가 가리키는 지점으로 프로그램 실행이 건너뛰도록 명령한다. 때문에 읽었던 코드를 다시 읽을 수도 있고, 구간을 반복할 수도 있고, 어떤 코드는 읽지 않고 넘기는 것도 가능하다. 자, 그럼 위 어셈블리어 사진에서 JMP를 찾아보라. 그리고 상상해보라. 당신은 코드 작성 중에 JMP가 어디를 가리키는지 눈으로 잘 따라갈 수 있을까? 짧은 코드라면 모를까 코드의 양이 늘면 늘수록 디버깅은 매우 힘들어진다. 디버깅이 힘들다는 말은 코드의 유지 보수가 매우 힘듦을 의미한다.
어셈블리어에서 이런 문제가 발생하는 이유는 어셈블리어가 비구조적 명령형 프로그래밍 언어이기 때문이다. 비구조적이란 말의 의미는 감이 바로 왔을 것이다. 말 그대로 코드가 구조화되어 있지 않고 그냥 나열되어있는 날 것 그대로라는 뜻이다. C언어는 절차 지향 프로그래밍 언어인데 절차 지향 프로그래밍은 구조적 명령형 프로그래밍과 동의어로 사용되기도 할 정도로 구조적 명령형 프로그래밍과 유사하다. 이제 이런 생각이 들 것이다. 그럼 C언어는 코드가 구조화된 명령형 프로그래밍 언어라는 뜻인데 어떤 식으로 구조화가 된 거지?
C언어는 프로시저로 구조화되었다. 프로시저는 루틴, 하위 프로그램, 서브루틴, 메서드, 함수라고도 하는데 C언어를 배우면서 다루었던 조건문(if, if~else, switch), 반복문(for, while), 함수 등이 모두 프로시저에 해당한다. 그리고 프로시저 단위로 구조화가 되면서 JMP 같은 녀석들(goto문)의 사용이 필요 없게 되었다. 덕분에 가독성이 크게 향상되고 유지보수에도 유리해졌다(비구조적 명령형 프로그래밍에 비해서지 객체 지향 프로그래밍에 비하면 유지보수가 나쁨).
절차 지향 프로그래밍의 개념이 이해되었는가? 잠깐 정리하고 넘어가자. 절차 지향 프로그래밍이란 프로시저 단위로 구조화된 명령형 프로그래밍이다.
객체 지향 프로그래밍이란?
이제 객체 지향 프로그래밍에 대해 이해할 준비가 되었다. 객체 지향 프로그래밍도 명령형 프로그래밍의 범주에 속한다. 그리고 여기서도 프로시저 단위로 구조화가 되어 있다. 여기까지만 들으면 절차 지향 프로그래밍과 다를 바가 없는데 뭐가 다른 것일까? 바로 프로시저를 사용하는 주체가 다르다. 절차 지향 프로그래밍은 개발자가 직접 프로시저를 다룬다. 원하는 프로그램을 구현하기 위해 개발자가 직접 프로시저들을 적재적소에 배치하고 실행되도록 한다. 반면, 객체 지향 프로그래밍은 프로시저를 사용하는 것은 객체라는 녀석이 한다. 그리고 개발자는 이 객체라는 녀석을 설계하고 이후 객체에게 실행되길 원하는 프로시저를 실행시키도록 요구한다.
객체를 설계한다는 말은 해당 객체가 사용할 수 있는 여러 프로시저들을 마련해둔다는 얘기다. 여기서 잠깐 혼란이 생길 수 있다. 아니 결국에는 개발자가 그 객체라는 녀석을 만들겠다고 프로시저들을 직접 적재적소에 배치한다는 것 아니냐! 그럼 이게 절차 지향 프로그래밍과 뭐가 다르단 말이냐! 자, 개발자가 결국 필요한 프로시저들을 만들고, 직접 다루기는 해야 한다는 점은 같으나 그 프로시저가 어떻게 실행되게 하느냐가 다르다. 실행되지 않을 프로시저를 만드는 행위는 무의미하므로 아무튼 프로시저를 만들었으면 이들이 실행이 돼야 할 것 아닌가?
절차 지향 언어에서는 개발자가 프로시저를 main() 함수 안에 배치한 순서대로 실행이 된다. 즉, 프로시저의 실행 유무와 실행 순서를 개발자가 직접 관여하게 된다는 것이다. 하지만 객체 지향 언어에서는 프로시저의 실행 유무나 실행 순서는 객체가 어떻게 행동하느냐에 달려 있다. 개발자가 만들어 둔 프로시저이지만 이들이 사용될지 말지, 언제 어떻게 사용될지 개발자가 알 수 없다는 의미다.
객체란?
객체라는 녀석이 뭔지, 개발자와는 어떤 관계인지 이해를 돕기 위해 예시를 하나 들어 보겠다. 당신은 KBS 뉴스가 보고 싶다. 방송국에서 송출되는 전파를 수신해서 이를 변환하고 영상과 소리로 출력해줄 무언가를 만들고자 한다(우리는 이게 TV라는 것을 알지만 TV라는 개념을 전혀 모른다고 가정). 그리고 당신은 너무 똑똑해서 이를 어떻게 구현할 수 있는지 아이디어를 가지고 있다(당신은 지금 프로그램을 개발하려는 개발자다). 당신은 LCD 패널, 안테나, 트랜지스터 회로, 스피커 등의 필요한 프로시저들을 만들었다. 그리고 안테나, 트랜지스터 회로, LCD 패널, 스피커를 차례로 연결했다(프로시저 배치). 안테나가 전파를 수신하고, 트랜지스터 회로에서 변환하고, LCD 패널로 화면을, 스피커로 소리를 출력한다(개발자가 의도한 대로 프로시저 실행). 당신은 KBS 뉴스를 볼 수 있게 되었다. 여기가지는 절차 지향 프로그래밍의 예다.
다음은 객체 지향 프로그래밍의 예다. 당신은 KBS 뉴스를 보고 싶어서 LCD 패널, 안테나, 트랜지스터 회로, 스피커 등의 필요한 프로시저들을 만들었다. 그리고 채널과 스피커 볼륨을 조절할 수 있는 스위치 등의 프로시저도 추가로 만들었다. 당신은 이들을 적절히 구성하고 하우징까지 씌웠다. 그렇다 당신은 TV(객체)를 만들어냈다. 여기서 TV는 객체의 역할을 한다. 당신은 TV를 켜고 스위치를 조금 조정하여 KBS 뉴스를 켰다(객체에 어떠한 프로시저 실행을 요구).
이제 객체와 객체 지향 프로그래밍에 대한 이해가 좀 가는가? 이래도 이해가 가지 않는다면 나로서는 여기까지가 한계다.. 이제 절차 지향 프로그래밍과 객체 지향 프로그래밍의 장단점을 비교해보고 왜 객체 지향 프로그래밍이 유지보수에 더 좋다는 것인지 알아보자. 당신은 이제 KBS 뉴스가 아니라 예능이 보고 싶어졌다. 절차 지향 프로그래밍의 예에서 만들었던 것은 TV가 아니다. 당신은 예능을 보기 위해 KBS 뉴스를 출력하던 것을 새로 분해하고 다시 만들었다. 이제 예능을 볼 수 있게 되었지만 만약 나중에 다큐가 보고 싶다면 당신은 분해하고 새로 조립하는 과정을 또 반복해야 한다. 객체 지향 프로그래밍의 예에서 당신은 TV의 스위치를 돌린다(객체에게 다른 채널을 출력하도록 요구). 당신은 이제 예능을 볼 수 있게 되었다. 당신이 나중에 다큐가 보고 싶다면 스위치를 다시 돌리면 된다.
왜 객체 지향 프로그래밍이 절차 지향 프로그래밍보다 유지보수가 뛰어난지 이해했을 것이다. 하지만 그렇다고 객체 지향 프로그래밍이 장점만 있는 것은 아니다. 절차 지향 프로그래밍은 프로그램 작성이 빠르고 실행도 빠르다. 반면 객체 지향 프로그래밍은 프로그램 작성이 오래 걸리고 코드가 많아진다. 실행도 절차 지향 프로그래밍에 비해 느리다. TV 비슷한 것을 급조하는 것과 TV 자체를 만들어버리는 것은 확연한 차이가 있다. 그리고 TV의 채널을 몇 개로 할 것인지, 소리 크기는 얼마를 최대로 할 것인지 등등은 아무도 정해주지 않는다. 채널 수를 너무 적게 하면 기껏 TV를 만들어 놓고 보고 싶은 것을 못 보게 되어 다시 뜯어고쳐야 할 수도 있고, 너무 많게 하면 TV 하나 만드는 데에 너무 많은 비용이 들어간다. 즉, 객체 지향 프로그래밍은 객체 하나 설계하는 것 자체가 벌써 일이다.
'공부 일지 > CPP 공부 일지' 카테고리의 다른 글
C++ 스마트포인터(unique_ptr, shared_ptr, weak_ptr) (0) | 2023.06.07 |
---|---|
C++17 객체 지향 언어와 객체 그리고 클래스(class)(1) (2) | 2022.02.10 |
C++17 Date and time utilities (0) | 2022.02.07 |
C++ | mutable 키워드 (0) | 2021.08.10 |
C++ | 범위 기반 for문 (0) | 2021.08.09 |