객체지향(OOP, Object Oriented Programming)

 

C++에서 객체는 class라는 문법으로 만들 수 있다. (class는 일종의 설계도라고 생각하면 된다.)

 

지금까지 Text RPG 코드 등과 같이 직접 만들었던 코드들은 절차 지향적 코드이다. 

이제부터는 본격적으로 게임 개발 등에서 많이 사용하는 객체지향을 이용할 것인데

객체지향은 말 그대로 각각의 객체들을 이용해서 원하는 로직을 만드는 것이다. 

즉 변수나 함수 등이 하나의 객체 안에 포함되어 있고 사용자는 그 객체를 불러와서

원하는 동작이나 로직 등을 쉽게 만들 수 있다.

 

class 내부에서 멤버 함수와 멤버 변수를 지정할 수 있으며 

class 안에서는 해당 멤버 변수를 어디에서든지 가져와서 사용할 수 있다.

보통 멤버 변수는 특정 객체 내의 멤버 변수라는 것을 나타내기 위해 

변수명 앞에 _(언더바) or m_ 등과 같이 써준다.

 

class를 이용해서 객체를 생성하면 무조건 생성자와 소멸자가 만들어진다. 

생성자는 여러개 존재할 수 있고 소멸자는 무조건 하나만 존재할 수 있다.

사용자가 직접 명시적으로 생성자를 선언할 수 있고 따로 명시적으로 생성자를 선언하지 않으면

컴파일러가 암시적으로 생성자를 선언한다.

하지만 이런 암시적인 생성자 선언은 원치 않는 상황이 발생할 수도 있으므로 

상황에 따라 명시적으로 선언하는 것이 좋다.

 

생성자의 종류는 크게 세 가지로 분류할 수 있다.

 

기본 생성자

타입 변환 생성자

기타 생성자

 

이 중에서 기본 생성자는 객체가 생성될 때 암시적이든 명시적이든 무조건 한 번은 호출되는

생성자이다. 사용자가 명시적으로 생성자를 선언하지 않으면 컴파일러가 암시적으로 생성하지만

사용자가 기본 생성자 포함 아무 생성자나 명시적으로 선언하면 컴파일러는 더 이상 기본 생성자를 

암시적으로 생성하지 않는다. 그렇기 때문에 다른 생성자를 직접 선언했다면 기본 생성자 또한 

명시적으로 선언해주어야 한다.

 

 

객체지향의 중요한 특성 세 가지는 다음과 같다.

상속성, 은닉성, 다형성

 

일단 상속성부터 정리해보자.

상속은 말 그대로 자식 객체가 부모 객체의 정보들을 그대로 물려받는 것을 의미한다.

즉 부모 객체의 멤버 함수나 멤버 변수들을 그대로 사용할 수 있다.

class a

{

public:

~~~~

}

 

class b : public a // 부모 a, 자식 b

{

 

}

 

위와 같이 상속을 선언할 수 있다. 부모 객체는 a이고 자식 객체는 b이다.

부모가 물려준 정보들을 그대로 사용할 수도 있고 아니면 자식 객체에서 해당 정보들을

재정의해서 사용할 수도 있다.

 

상속에서의 생성자와 소멸자의 개념도 조금 달라진다.

다른 함수나 변수 같은 경우 부모의 정보들을 그대로 받아와서 사용하지만 생성자의 경우는 

자식 객체에서 자식 생성자가 실행되기 직전(선처리 영역)에 부모의 생성자를 호출하고 그 이후에 

자식의 생성자를 실행한다. 소멸자 같은 경우 자식 소멸자가 먼저 실행되고 그 후에 부모의 소멸자를 호출한다.

 

두 번째로 은닉성에 대해 알아보자.

객체에서의 은닉성은 외부에 노출 시키면 안 되는 중요한 함수 등을 감추기 위해서 

사용한다. 예를 들어 객체 안에서만 해당 함수를 호출할 수 있다거나 자신 혹은 자식 객체에게만

함수 접근을 허용하는 경우가 있다. 이러한 은닉성은 아래와 같이 크게 세 가지로 구현할 수 있다.

 

public, protected, private

 

위 세가지는 영어 뜻과 기능이 흡사하다.

public은 어디에서든지 객체 내부의 함수를 호출할 수 있다. 누구나 접근이 가능하다. 

protected는 public과 private의 중간 역할을 하는 것으로 객체 자신 및 자식 객체에 한하여 

함수에 접근이 가능하다.

private는 객체 내부에서만 함수 호출이 가능하고 자식 및 외부에서는 접근이 불가능하다.

 

은닉성은 객체 내부에서만 사용하는 것이 아니라 상속을 할 때에도 사용된다.

부모 객체를 받아올 때 어떤 타입으로 받아오냐에 따라 자손들에게 부모 객체 정보 사용을 

허용할지 숨길지 결정할 수 있다. 

 

세번째로 다형성이 있다. 

다형성은 겉은 똑같지만 기능이 다르게 동작하는 것을 말한다.

다형성에는 오버로딩과 오버라이딩이 있다.

오버로딩은 함수의 이름을 재사용하는 것을 말하며

오버라이딩은 부모 클래스의 함수를 자식 클래스에서 재정의하는 것을 말한다.

 

또한 다형성에는 정적 바인딩, 동적 바인딩이라는 개념이 있고 

일반 함수가 정적, 가상 함수가 동적 바인딩을 사용한다.

객체 타입 변수를 여럿 생성하고 해당 변수들을 통합적으로 관리 및 사용할 때 사용되는데

가상 함수는 객체 타입에 따라 해당 객체의 주소를 따로 저장해놓고 호출할 때 해당 객체 타입에 맞는

객체로 이동해 내부에 있는 함수를 호출할 수 있다. 즉 부모 객체 내부의 함수가 호출되는 일반 함수와 달리

가상 함수는 객체 타입에 맞는 자식 객체 내부로 이동해서 자식 객체 내부에 오버라이딩된 함수를 호출할 수 있다는

소리이다. 

이와 관련해서는 차근 차근 실습을 해보면서 좀 더 공부해보자.

 

 

 

 

'프로그래밍 언어 공부 > C++' 카테고리의 다른 글

연산자 오버로딩  (0) 2022.06.18
초기화 리스트  (0) 2022.06.17
알고리즘 연습문제  (0) 2022.06.11
자주 쓰이는 함수  (0) 2022.06.08
Text RPG ver.2 (포인터, 참조 등 활용)  (0) 2022.06.08

strcpy(a, b);

문자열을 복사하는 함수

b의 문자열을 a에 복사한다. 그리고 a의 값을 리턴한다.

하지만 strcpy 함수는 오래된 함수이기 때문에 잘못 사용하면 버퍼 오버플로우가 발생할 수도 있다.

그래서 오버플로우를 막기 위해 나온 것이 아래의 함수이다. 

 

strcpy_s();

사용법은 strcpy 함수와 동일하다.

 


strlen();

문자열의 길이를 반환하는 함수

 

ex)

int a[100] = "Hello"

int b = strlen(a);

cout << b;

 

출력값 : 5

(주의할 점은 a 배열에 실질적으로 잡혀있는 크기는 6이다. 문자열의 끝을 알리는 '\0'가 포함되어 있기 때문이다.

즉 strlen 함수는 '\0'를 제외한 나머지 문자열의 크기를 반환한다.)

 


sizeof();

자료형의 크기를 반환하는 함수

 

ex)

int a[100] = "Hello"

int b = sizeof(a);

cout << b;

 

출력값 : 100

 


strcat(a,  b);

두 문자열을 하나로 붙여주는 함수

a 문자열에 b 문자열을 붙인다.

 


strcmp(a, b);

두 문자열을 비교하는 함수이다. 

두 문자열이 동일하다면 0을 리턴하고

두 문자열 다르다면 비교해서 a가 b보다 클 시 1을 리턴하고 

작을 시 -1을 리턴한다.

 


 

'프로그래밍 언어 공부 > C++' 카테고리의 다른 글

객체지향의 개념 정리  (0) 2022.06.16
알고리즘 연습문제  (0) 2022.06.11
Text RPG ver.2 (포인터, 참조 등 활용)  (0) 2022.06.08
참조  (0) 2022.06.02
포인터와 간접 멤버 연산자  (0) 2022.05.31

참조

 

참조란 C++에 있는 문법으로써 기능적으로 포인터와 동일한 역할을 한다.

 

1-0 코드
1-1 코드 결과

1-0 이미지와 같이 포인터는 변수의 주소 값을 저장하고 해당 주소 값을 이용해서

주소 값 안에 데이터를 수정하거나 주소 값 자체를 조작할 수 있다.

 

이와 동일한 역할을 하는 '참조'는 로우 레벨 언어 측면에서 보면 포인터와 동일하게

해당 주소값을 받아서 원본 데이터를 수정하는 역할을 한다. 

 

하이 레벨 언어 측면에서 보면 포인터는 주소를 직접 저장하는 반면 참조는 특정 변수에 

별칭을 지어주는 느낌으로 이해하면 된다. 

 

다른 예시를 통해 좀 더 살펴보자.

 

2-0 코드
2-1 코드 결과

 

구조체 Info를 선언하고 초기값을 설정해주었다.

그리고 매개변수를 포인터로 선언하는 함수와 참조로 선언하는 함수가 존재한다는 것을

미리 선언해주었다.

 

메인 함수에서 Info 구조체를 이용할 qqq 변수를 선언하고

각 함수를 호출하면서 동시에 해당 함수에 의해 변화되는 qqq의 값을 확인하기 위해 출력문을 중간중간 넣었다.

함수를 호출할 때 포인터 매개변수를 가지는 함수는 주소값을 전달해주기 위해 & 타입을 앞에 붙여줬지만

참조는 &를 붙여줄 필요가 없기 때문에 변수를 그냥 매개값으로 넣어주었다.

 

이제 미리 선언했던 각 함수를 상세 정의해야 한다.

먼저 포인터 함수를 먼저 정의했고 간접 멤버 연산자(->)를 이용해 원본 데이터의 값을 각각 수정해주었다.

 

두 번째 함수인 참조 함수는 포인터와 똑같은 기능적 역할을 한다. 로우 레벨 측면에서 보면 

동일하게 해당 주소를 가져와서 원본 데이터를 수정하는 방식이다. 하지만 우리 눈에는(하이 레벨 언어 측면) 포인터보다

훨씬 간단하고 편하게 사용할 수 있다는 장점이 있다. 

 


주의할 점

 

참조는 보는 바와 같이 포인터와 동일한 기능 및 역할을 하고 포인터보다 훨씬 간편하고 쉽게 사용할 수 있다는

장점이 있지만 조심할 점은 포인터와 완벽히 동일한 것은 아니다. 

 

포인터는 아무런 값도 가지지 않고 존재할 수 있지만, 즉 NULL 값을 가질 수 있지만

참조는 무조건 특정 값을 가지고 있어야 한다. 

 

또한 코드를 잘 모르는 다른 사람이 보기에 참조는 원본 데이터를 수정하는지 아닌지 헷갈릴 수가 있다.

원치 않게 원본 데이터가 훼손될 수도 있다는 것이다.

 

이것의 해결방법으로는 상수 화가 있는데 여기서도 포인터와 차이점이 있다. 

 

포인터는 상수화 const를 * 앞에 붙이냐 뒤에 붙이냐에 따라 상수화가 달라진다. 

* 앞에 const가 붙었을 경우 해당 주소에 있는 원본 데이터가 상수화된다. 

* 뒤에 const가 붙었을 경우 해당 주소 값이 상수화 된다.

 

반면 참조 같은 경우 & 앞에 붙이는 것 밖에 할 수 없으며 원본 데이터가 상수화 된다.

 

둘의 비슷한 기능을 하기 때문에 실제로 둘 다 많이 사용되는 문법이다.

상황에 따라 융통성 있게 사용하면 좋을 것 같다.

 

 

포인터

 

C++에서의 포인터 개념은 C언어와 크게 다르지 않다. 

포인터는 주소를 사용한다. 

주소를 사용하는 이유는 우리가 특정 메모리 공간에 있는 값을 다른 장소에서

수정할 수 있도록 하기 위해서 사용한다.

 

1-0

1-0 이미지와 같이 기존에는 main 함수 내에 지역변수로써 선언된 a 변수 값과 

aaa 함수 내에 매개변수로써 선언된 a 변수 값이 저장된 공간이 다르기 때문에 

aaa 함수 내에서 a 변수(매개변수)에 값을 바꾸더라도 main 함수 내에 있는 a 변수(지역변수)에 영향을 미치지 않는다.

결괏값은 당연하게도 1이 출력된다.

 

하지만 포인터를 사용하면 얘기가 달라진다.

1-1

1-1 이미지에서 12번 라인을 보면 

aaa 함수를 호출하고 매개 변수로써 a 변수(지역변수)의 주소 값을 주었다.

해당 주소 값을 저장하기 위해 aaa 함수의 매개 변수를 포인터 변수로써 선언하였고 

6번 라인에 *a와 같이 해당 주소 안으로 이동하여 100이라는 값을 넣어주었다.

 

즉 main 함수 안에서만 사용할 수 있던 지역 변수를 main 함수 밖에서 접근하여 값을 

수정해준 것이다. 결괏값은 1-0 이미지 때와 다르게 100이 나온다.

 

다시 한번 정리하면

int number = 1;

int* a = &number; > 주소를 저장하는 바구니를 선언하고 해당 바구니에 number의 주소를 저장한다.

*a = 100; > 저장된 주소 안으로 이동해서 100이라는 값을 넣어준다.

 

최대한 간단하게 정리해보았다.

 


간접 멤버 연산자

 

2-0

 

2-0 이미지에서 보이듯 간접 멤버 연산자는 " -> " 로 표현한다.

해당 연산자는 간접 연산자(*)와 구조체의 특성을 동시에 표현할 수 있다.

 

우선 구조체를 struct 명령을 통해 정의하고 메인 함수 내에 해당 구조체를 사용하기 위해

hello를 선언했다.

 

이후 포인터를 이용해 해당 hello 구조체 변수의 주소를 Hello에 저장하였고

포인터로 주소 내부에 접근해 값을 수정해주었다.

 

마지막으로 간접 멤버 연산자를 이용해 포인터로 값을 수정했을 때보다 간편하게 표현하였다.

20, 21번 라인과 29, 30번 라인은 동일한 동작을 하는 명령이다.

 

2-1 결과값

 

구조체란

여러 자료형을 가진 변수들을 하나로 묶어 새롭게 정의해서 사용할 수 있는 사용자 정의 타입이다.

실습을 통해 구조체를 이해해보자

 

1-0 구조체 실습

 

우선 struct 명령을 이용해서 구조체를 정의해준다.

struct [구조체명]

 

구조체 안에는 int타입뿐만 아니라 다양한 타입들의 변수들이 포함될 수 있으며 

해당 변수들을 구조체 멤버라고 한다.

 

구조체명을 이용해서 구조체 변수를 정의할 수 있다. 

선언한 구조체 변수를 통해 구조체 멤버를 사용할 수 있다.

 

1-0 이미지와 같이 필자는 player와 monster라는 구조체 변수를 선언하였고 

해당 구조체 변수를 통해 구조체 멤버 type에 각각 정수를 저장하고 출력하는 코드를 만들었다.

 

 

 

 

 

 

공부했던 내용을 바탕으로 직접 Text RPG 코딩을 해보았다. 

포인터는 아직 배우지 않아서 사용하지 않았다.

'프로그래밍 언어 공부 > C++' 카테고리의 다른 글

포인터와 간접 멤버 연산자  (0) 2022.05.31
구조체  (0) 2022.05.30
함수 매개변수 기본값 설정 / 오버로딩 개념  (0) 2022.05.29
함수와 스택 프레임  (0) 2022.05.27
열거형  (0) 2022.05.26

+ Recent posts