함수와 클래스에서 유형을 매개변수화하는 기능으로, 컴파이럴에 의해 구체적 유형으로 대체될 수 있는 제네릭 유형입니다.
형식은 template<typename T>입니다.
아래 예시와 같이 왼쪽에 여러개로 오버로딩된 maxValue 함수들이 오른쪽의 템플릿을 사용한 하나의 maxValue로 간략하게 포현할 수 있습니다.
템플릿의 대표적인 예시.
클래스 템플릿은 클래스의 이름 위에 template<typename T>라고 작성하면 되며, 만약 .h와 .cpp 파일로 나눈다면 .h에만 template<typename T>를 작성하면 되고, .cpp 파일에서 범위 지정 연산자 앞에있는 클래스 이름에 <T>를 붙여야됩니다. ex) Stack<T>::push
template<typename T = dataType> 의 형식으로 default dataType를 정할 수 있습니다. 또한, template<typename T, int capacity> 의 capacity처럼 비형식 매개변수도 사용할 수 있습니다. 해당 템플릿의 예시는 Stack<std::string str, 500> 이런식으로 사용할 수 있습니다.
- 벡터(vector)
벡터는 배열처럼 사용할 수 있으며, 벡터의 크기가 필요할 경우 자동으로 증가시킬 수 있습니다.
vector<elementType> vectorName의 형식으로 선언할 수 있습니다.
vector도 string처럼 하나의 객체입니다. 그렇기 때문에 #include <vector>를 입력해야 사용할 수 있습니다.
일반 배열처럼 사용가능하며, 별도의 함수들도 존재합니다. ex) size(), push_back(), pop_back() etc...
만약 크기가 고정된다면 배열이 더 효율적이지만, 크기가 유동적이라면 vector가 더 효율적입니다.
- 포인터는 다른 변수의 메모리 주소를 저장하는 변수입니다. 기본적으로 주소를 저장하기 때문에 4byte를 사용합니다.
- 선언은 dataType* pVarName 의 형식을 사용합니다.
- 포인터는 다른 변수의 메모리 주소를 저장하기 때문에 주소를 반환하는 & 주소 연산자를 사용합니다.
- 포인터 변수는 * 간접 연산자를 사용하여 역참조를 할 수 있습니다. 방법은 (*pVarName)입니다.
- 배열 이름은 실제로 배열의 시작 주소를 나타냅니다. ex) list[6]의 list == 배열의 시작 주소.
- this 포인터는 호출 객체 자신을 가리킵니다. 보통 클래스의 숨겨진 데이터 필드를 참조할 때 사용합니다.
typedef - 기존의 데이터 유형에 대한 새로운 동의어를 정의하는 구문입니다. ex) typedef int* intPointer; intPointer p; == int* p;
동적 영구 메모리 할당
- new 연산자를 사용하여 원시 유형의 값, 배열, 객체에 대해 실행 시 영구적인 메모리를 생성할 수 있다.
- dataType* pValueName = new dataType(size), 배열이면 new dataType[size] 로 사용 가능하며, 객체일 경우 className* pValueName = new className() 혹은 new className 로 사용 가능합니다.
- 동적 영구 메모리 할당한 변수들은 delete 연산자를 이용하여 명시적으로 삭제해야 합니다.
- 만약 포인터가 가리키는 메모리를 삭제하기 전에 실수로 포인터를 재할당한다면, 포인터가 전에 가리키던 메모리는 삭제할 수 없게 되는데, 이를 메모리 누설이라고 한다.
- guessCh : 입력받은 문자 ch와 word를 비교하여 맞는 문자가 있는지 확인합니다. 만약 1개라도 맞는게 있다면 star에 *를 문자로 교체하고, collectCount를 증가시킵니다. 만약 맞는게 없다면 해당 문자 ch는 word에 없는 문자라고 출력하고 missCount를 증가시킵니다.
- playHangman : while문을 사용하여 checkStar가 false를 반환하기 전까지 계속 반복합니다.
main.cpp
#include "hangman.h"
int main() {
srand(time(0));
while (true) {
std::string words[10] = { "write", "that", "java", "korea", "master", "location", "program", "consider", "hello", "world"};
Hangman game(words[rand() % 10]);
game.playHangman();
std::cout << std::endl << "Do you want to guess for another word? Enter y or n>";
char answer;
std::cin >> answer;
if (answer == 'n') break;
}
return 0;
}
기본적으로 무한 루프를 사용합니다.
임의의 단어들을 생성하여 Hangman 객체인 game에 1개의 단어를 입력합니다.
그리고 playHangman 함수를 실행하여 게임을 시작하고, 게임이 끝나면 다시 한번 더 할 것인지 물어봅니다. 만약 사용자가 y를 입력하며 다시 hangman 게임을 시작하고, n을 입력하며 무한 루프문을 탈출하여 프로그램을 종료합니다.
- class는 객체 지향 프로그래밍에서 객체의 속성과 행동을 정의해주며, 즉 객체에 대한 설계도입니다.
- class도 데이터 유형입니다. 그래서 객체의 선언과 생성을 위해 클래스를 사용할 수 있습니다.
- class의 생성자는 class의 이름과 동일해야 하며, 생성자는 2가지로 나뉩니다.
인수가 없는 생성자 : 인수를 가지지 않는 생성자로, 굳이 작성을 안해도 기본적으로 제공하는 생성자입니다.
인수가 있는 생성자 : 인수를 가지는 생성자로, 객체를 생성할 때 인수를 같이 넣어서 생성해야된다.
- 객체는 클래스의 인스턴스로, 이름을 통해 객체의 멤버에 접근하기 위해서는 점 연산자(.)를 사용한다.
- 객체의 상태 : 현재 값의 데이터 필드(속성)로 표현 / 행동 : 함수 세트로 정의
- class는 public 과 private 키워드를 사용합니다.
public : 모든 클라이언트에서 접근 가능
private : 클래스 안에서만 접근 가능
- 헤더 파일에서 class를 정의하고, 다른 파일에서 클래스를 구현이 가능하다. 이렇게 구현함으로써 클래스 정의와 구현을 분리할 수 있습니다.
- 헤더 파일이 여러 번 포함되는 것을 방지하기 위해 #ifndef 지시자를 사용할 수 있다.
- 보통 접근자에는 함수 이름에 get을 붙이고, 변경자에는 함수 이름에 set를 붙인다.
- 문제 풀이 -
9.11(EvenNumber 클래스) 다음 내용을 포함하여 짝수를 표시하는 EvenNumber 클래스를 정의하여라. - 객체에 저장된 정수 값을 표시하는 int 형의 value 데이터 필드 - 0 값으로 EvenNumber 객체를 생성하는 인수 없는 생성자 - 특정 값으로 EvenNumber 객체를 생성하는 생성자 - 객체에 대해 int 값을 반환하는 getValue() 함수 - 객체에서 현재 짝수 값 이후의 다음 짝수 값을 나타내는 EvenNumber 객체를 반환하는 getNext() 함수 - 객체에서 현재 짝수 값 이전의 앞 짝수 값을 나타내는 EvenNumber 객체를 반환하는 getPrevious() 함수 클래스 구현 후, 입력받은 수에 대한 getNext() 와 getPrevious() 함수를 호출하여 이들 수를 화면에 출력하는 테스트 프로그램을 작성하여라.