객체지향 프로그래밍과 클래스 (Object Oriented Programming and Class) 본문
객체지향 프로그래밍과 클래스
객체지향 프로그래밍(Object Oriented Programming)을 줄여서 OOP라고 부른다.
객체지향 프로그래밍을 클래스와 함께 살펴보자.
예를 들어 친구들에 대해서 데이터를 정리 해놓고
원할 때 그 친구에 대해서 출력해주는 프로그램을 만든다고 생각해보자.
친구에 대해서 생각해보면 이런 것들이 떠오를 수 있다.
정리해보자면
이렇게 정리할 수 있다.
그리고 이 데이터들을 전부 출력해주는 함수를 만든다고 생각해보자.
이렇게 작성할 수 있다.
이때 우리가 더 많은 친구들에 대해서 데이터를 저장하려고 한다면 array나 동적할당배열 같은 것들을 써야 한다.
친구가 늘었다 줄었다 할 수도 있으니까 vector를 사용해보자.
이런 식으로 접근을 해야 할 것이다.
이 중에 데이터 하나를 출력해 보고 싶다면 print 함수를 이용해야 할 것이다.
만약에 이렇게 한 친구만 있는 구조라고 한다면
print(name, address, age, height, weight); 이렇게 하면 친구에 대해서 쫙 나올 것이다.
매번 할 때마다 [0] 쳐주는 거 번거롭고 지금 코드가 많이 길어지고 있다.
이때 좀 더 편리하게 만들어 줄 수 있는 존재가 한 가지 있다.
이전에 구조체 struct에 대해 배운 적 있다.
데이터들을 묶어서 하나의 의미를 부여하는 것이다.
Friend라는 개념으로 struct를 만들었다.
그 struct에 데이터를 싹 집어넣으면
이렇게 한 덩어리가 되는 것이다.
초기화도 해줘야 하는데
초기화를 이렇게 uniform initialization 하는 방법도 있고
버전 낮은 컴파일러 쓰는 분들은
이런 식으로 넣을 수도 있다.
이런식으로 uniform initialization 할 수도 있다.
그다음에 print를 하려고 하는데
이 sh에 대해서 print를 하려고 한다.
그러면
이렇게 출력을 할 수 있다.
. 찍는 것은 멤버를 선택해주는 것이다.
이 struct 안에 들어있는 모든 변수들을 멤버라고 부른다.
member variable name, member variable address, member varianle age 등등 이렇게 부를 수 있다.
그런데 지금 보면 들어가는 게 너무 많다.
코딩할 때 만약 sh 말고 다른 친구가 생겨서 그 친구에 대해서 출력하려면
이 과정을 또 반복을 해야 한다. 손이 많이 가고 불편하다.
그래서 이 print의 매개변수를 이렇게 하나하나 받을 게 아니라
struct 하나로 받아버리자라고 생각해 볼 수 있다.
지금 print 함수를 복붙 했는데
같은 이름의 함수가 두 가지 있어도 안에 들어가는 파라미터가 다르면
함수 overloading이 되기 때문에 다른 함수로 인식을 해준다고 말씀드린 적 있다.
이번엔 fr 하나만 넣어주면 되니까 훨씬 간결하다.
아주 깔끔해졌다.
사실 여기도 fr.이 너무 중복된다는 느낌이 든다.
다음으로 해결할 수 있는 방법은
이 함수를 잘라서 struct 안에 넣는 것이다.
이렇게 들어가면 이 print 함수도 Friend라는 struct의 멤버가 된다.
name, address, age, height, weight, print 도 모두 멤버다.
그렇다면 서로 공유를 할 수 있게 된다.
print 함수가 위 friend 데이터들에 바로 접근할 수 있게 되었다.
그래서 이렇게 간접적으로 뭐를 거쳐갈 필요가 없는 것이다.
같은 멤버이기 때문에 직접 접근할 수 있다.
그래서 const Friend &fr는 빼버림.
fr이 더 이상 필요 없어서 빼는 순간 에러가 뜬다.
왜냐면 같은 멤버이기 때문에 name 같은 데이터에 직접 접근할 수 있기 때문이다.
이렇게 지워 줄 수 있다.
address 선택하면 print 함수에 있는 address에도 선택되는 걸 볼 수 있다.
같은 멤버이기 때문에 같은 struct 영역 안에 들어있으니까 얼마든지 접근할 수 있다.
훨씬 깔끔해졌다.
이렇게 만들어놓으면 main에서
sh.print(); 이렇게 하면
sh라는 존재가 직접 print라는 작업을 하는 것처럼 보인다.
프로그래머가 이해하고 디자인하고 설계하기가 훨씬 편해진다.
이렇게 데이터와 기능이 묶여있는 것을 오브젝트라고 부른다.
그리고 이 struct에서도 이 function기능을 넣을 수 있는데
보다 많은 기능, 많은 객체지향 프로그래밍 기법들을 다룰 수 있게 만들어 주는 것이 class이다.
struct를 class로 바꿔버렸다.
단순한 기능을 할 때는 class 대신에 struct 써도 크게 문제 될 것은 없다.
그런데 일반적으로는 struct를 사용할 때는 데이터를 묶는 데에만 쓰고
기능을 넣을 때는 class를 쓰자는 게 일반적이다.
그리고 C 문법에서는 struct에 기능(예를 들어 위 예제에서는 print함수)을 넣을 수가 없다.
C++에서는 구조체 struct 안에도 function이 들어갈 수 있는데 C는 안된다.
그리고 다음으로 한 가지 더 추가해줘야 한다.
public이라는 access specifier(접근 지정자)를 추가해주게 된다.
이 access specifier에는 public, private, protected 세 가지가 있다.
public과 private 두 가지는 다음 포스팅에서 알려드리겠다.
protected는 상속을 배운 다음에 다시 설명하겠다.
일단은 public 쓰면 된다 정도로만 생각하자.
그래서 정리를 하면 object 객체라는 것은 개념이다.
이런 데이터와 friend를 출력해주는 기능을 묶여있는 것들을 개념적으로 생각하는 게 객체 object이다.
그리고 이 객체라는 개념을 프로그래밍 언어로서 구현하는 부분
이 부분으로 구현을 해놨는데
이때 사용되는 키워드가 class이다.
class란 object라는 개념을 문법으로 구현할 때 사용하는 것이다.
그다음에 또 하나 알아두면 좋은 것이 있는데
여기서 Friend 자체를 사용자 정의 자료형처럼 사용을 하고 있다.
그 말은 즉, Friend 자체를 class로 정의하는 것 만으로는 메모리가 할당되지 않는다.
위 예시처럼 변수처럼 이름을 넣고 선언을 해줘야지만 메모리를 차지한다.
이렇게 실제로 메모리를 차지하도록 정의해주는 것을 instantiation이라고 부른다.
그리고 이 변수 sh를 우리가 표현하고자 하는 object 혹은
이 object를 구현하기 위해 만든 class의 instance라고 부른다.
프로그래밍을 할 때 어떤 것의 실존 여부를 따질 때에는 얘가 메모리에 자리가 있는지 없는지로 판단한다.
sh를 주소를 찍으면 주소가 나올 것이다.
하지만 이 Friend라는 class 이 개념은 주소를 찍을 수가 없다.
왜냐면 아직 instantiation이 되지 않은 것이기 때문이다.
조금 헷갈릴 수 있지만 결국은 메모리에 존재를 하냐 하지 않느냐의 차이다.
데이터 타입과 실제로 그 데이터 타입으로 메모리에 만들어진 데이터 혹은 변수의 차이라고 생각하면 된다.
그리고 더 설명드리자면 위에서
이런 식으로 vector를 각각 만드려니까 힘들었다.
이런 방식으로는 코딩하지 않을 거다.
더 쉬운 방법이 있는데 굳이 손 많이 가고 타이핑 많이 해야 하는 방식으로 코딩할 필요는 없다.
그리고 타이핑을 좀 이상하게 많이 한다 싶으면 분명히 오류가 생길 가능성이 높다.
그래서 코드는 짧고 간결할수록 무조건 좋다.
친구가 여러 명이라고 생각을 해보자.
그러면 Freind의 vector를 만들어버리면 된다.
그리고
이렇게 하면 일단 친구 두 명을 저장할 공간이 생긴 것이다.
그걸 가지고 작업을 하면 된다.
그런데 이렇게 출력하려고 할 때
print로 이렇게 하나하나 찍을 필요가 없다.
my_friends 하고 0번째 친구 print()
my_friends 하고 1번째 친구 print() 이렇게 하면 된다.
물론 지금은 데이터를 넣지 않아서 친구 이름이 나오거나 하지는 않는다.
이때 만약 친구가 1000명이라면 다 어떻게 이렇게 일일이 찍을 것인가?
이럴 때 for문으로 돌려주면 된다.
이렇게 하면 아주 간결해진다.
같은 기능을 밑에 주석 처리한 부분처럼 코딩을 한다고 생각하면 아주 정신이 없다.
for (auto& ele : my_friends) ele.print();
이렇게 하면 훨씬 깔끔하고 보기가 좋다.
보기가 좋으면 프로그래머의 실수가 줄어든다.
객체지향은 프로그래머들을 혼란스럽게 하거나 복잡하게 만들려고 한 게 아니고
실수할 확률을 줄여주고 프로그래밍 시간을 줄여주려고 도입이 된 아주 고마운 기술이다.
몇 가지 더 설명드리자면
멤버라는 것을 표현해주기 위해서 앞에 m_ 를 붙이는 경우가 많다.
이름 바꿀 때는 오른쪽 클릭해서 rename(이름바꾸기) 하거나 Ctrl + R 해서 한꺼번에 바꿔주면 된다.
예전에는 이렇게 m_를 붙이는 게 당연하다고 생각을 했었다.
그런데 최근에는 코딩 스타일이 좀 바뀌었다.
m_ 치는 것도 타이핑 양이 들기 때문에
이렇게 뒤에만 언더바를 붙여주는 경우도 있고
앞에 언더바를 붙여주는 것도 요즘 많이 쓴다.
실제로 해보면은 멤버를 찾기 위해서 변수명을 친다음에 맨 끝에 언더바를 치는 것보다는
일단 언더바를 치고 그다음에 변수명을 치는 게 조금 더 편한 측면이 있다.
그냥 각자 일하는 곳 규격에 맞춰서 쓰면 된다.
우선 교과서에서는 보통 m_를 많이 쓴다.
그리고 반복해서 말씀드리자면 아까 struct에도 function을 집어넣었었는데
struct에는 function을 잘 안 넣도록 하자는 게 일반적이다.
그렇다면 struct에도 function이 들어갈 수 있는데 struct와 class의 차이가 뭐지? 궁금할 수 있다.
일단 struct에는 이 access specifier가 들어가지 않는다.
자세한 차이점은 추후 포스팅하겠다. 점점 class와 struct는 많이 다르구나를 느낄 수 있을 것이다.
개념정리를 하자면
객체 지향 프로그래밍은 속성과 동작을 함께 결합하여 재사용 가능한 패키지로 만드는 기능을 제공한다.
누가 주체이고, 어떤 행동을 하는지 분명히 알 수 있다.
함수를 작성하는데 초점을 맞추기보다는 명확하게 정의된 동작 세트가 있는 객체를 정의하는데 중점을 둔다.
때문에 이 패러다임을 "객체 지향"이라고 한다.
즉, 프로그램을 단순히 데이터와 처리방법으로 나누는 것이 아니라,
프로그램을 수많은 '객체'라는 기본단위로 나누고 이 객체들의 상호작용으로 서술하는 방식이다.
객체 지향은 프로그램을 보다 모듈화 된 방식으로 작성할 수 있고, 더 쉽게 쓰고 이해할 수 있으며,
더 높은 수준의 코드 재사용성을 제공한다.
또한, 이러한 객체들은 프로그래머가 객체들과 어떻게 상호작용하는지
그리고 그것들이 다른 객체들과 어떻게 상호작용하는지를 정의함으로써
프로그래머의 데이터로 작업하는 더 직관적인 방법을 제공한다.
컴퓨터과학에서 객체 또는 오브젝트는 저장공간에서 할당되어 값을 가지거나 식별자, 자료구조, 함수가 될 수 있다.
프로그래밍 언어는 변수를 이용해 객체에 접근하므로 객체와 변수라는 용어는 종종 함께 사용된다.
그러나 메모리가 할당되기 전까지 객체는 존재하지 않는다.
절차적 프로그래밍에서 하나의 객체는 자료나 명령을 포함할 수 있지만 두 가지를 동시에 포함하지는 않는다.
(명령은 프로시저나 함수의 형태를 가진다.)
객체 지향 프로그래밍에서 객체는 클래스의 인스턴스이다.
클래스 객체는 자료와 그 자료를 다루는 명령의 조합을 포함하여 객체가메시지를 받고 자료를 처리하며
메시지를 다른 객체로 보낼 수 있도록 한다.
객체라는 용어에 혼란이 올 수 있다.
전통적인 프로그래밍에서 '객체'는 값을 저장하는 메모리 조각이다.
객체 지향 프로그래밍에서 '객체'는 속성과 동작을 결합한 객체라는 것을 의미한다.
'💘 C++ > 객체지향의 기초' 카테고리의 다른 글
생성자 멤버 초기화 리스트 (Constructor member initializer list) (0) | 2022.08.30 |
---|---|
생성자 (Constructor) (0) | 2022.08.30 |
캡슐화, 접근 지정자, 접근 함수 (Encapsulation, Access Specifiers, Access Functions) (1) | 2022.08.24 |