C++ 공부 15일 차

 

오늘은 템플릿과 벡터에 대해 공부했습니다.

 - 템플릿(template)

  • 함수와 클래스에서 유형을 매개변수화하는 기능으로, 컴파이럴에 의해 구체적 유형으로 대체될 수 있는 제네릭 유형입니다.
  • 형식은 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가 더 효율적입니다.

 

'Week4' 카테고리의 다른 글

Week 4 - 21.08.18  (0) 2021.08.18
Week 4 - 21.08.17  (0) 2021.08.18
Week 4 - 21.08.16  (0) 2021.08.17

C++ 공부 14일 차

 

오늘은 포인터와 동적 할당에 대해서 공부했습니다.

  • 포인터

 - 포인터는 다른 변수의 메모리 주소를 저장하는 변수입니다. 기본적으로 주소를 저장하기 때문에 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 연산자를 이용하여 명시적으로 삭제해야 합니다.

 - 만약 포인터가 가리키는 메모리를 삭제하기 전에 실수로 포인터를 재할당한다면, 포인터가 전에 가리키던 메모리는       삭제할 수 없게 되는데, 이를 메모리 누설이라고 한다.

'Week4' 카테고리의 다른 글

Week 4 - 21.08.19  (0) 2021.08.19
Week 4 - 21.08.17  (0) 2021.08.18
Week 4 - 21.08.16  (0) 2021.08.17

C++ 공부 13일 차

 

오늘은 객체지향에 대한 개념을 공부했습니다. 이번 챕터부터 문제들의 난이도가 많이 올라서 내일 문제 풀이를 추가로 올리겠습니다.

 

객체지향 설계 지침

1. 결합성(Cohesion)

 - 클래스는 단일 요소를 설명하고 모든 클래스 동작은 분명한 목적을 제공하기 위해 함께 논리적으로 부합되어야합니다. 

 

2. 일관성(Consistency)

 - 이름 명명을 표준 프로그래밍 형식과 이름 명명 규칙을 따르며, 일관성 있게 이름을 선택하여아 한다. 또한, 인수가 없는 생성자를 일관성 있게 사용하는게 좋으며, 만약 사용하지 않는다면 주석문에 기록해 놓는게 좋다.

 

3. 캡슐화(Encapsulation)

 - 사용자가 클래스의 데이터에 직접 접근할 수 없게하기 위해서 private 변경자를 사용하고, get 함수(읽기)나 set 함수(갱신)를 이용하여 클래스의 데이터에 접근할 수 있도록 한다.

 

4. 명확성(Clarity)

 - 클래스는 설명하기 쉽고 이해하기 쉬운 명확한 규칙을 가져야합니다. 많은 다른 조합과 명령, 환경에서 클래스를 통합할 수 있지만 다른 데이터로부터 유도될 수 있는 데이터는 선언하지 않아야 한다.

 

5. 완성도(Completeness)

 - 클래스는 많은 사용자들이 사용할 수 있도록 설계되어야 합니다. 속성과 함수를 통해 사용자 정의를 위한 다양한 방법을 제공해야 한다.

 

(21.08.18 수정 - 문제 추가)

  • 10.15(게임: 행맨) ***
    임의로 한 단어를 생성하고, 사용자가 한 번에 한 문자만을 추측하도록 하는 행맨(hangman) 게임을 작성하여라.

hangman.h

#pragma once
#ifndef HANGMAN_H
#define HANGMAN_H

#include <iostream>
#include <string>
#include <cstdlib>
#include <ctime>

class Hangman {
public:
  Hangman(std::string& problemWord);
  char inputChar();
  bool checkChStar(char ch);
  bool checkStar();
  void guessCh(char ch);
  void playHangman();

private:
  int state;
  int collectCount;
  int missCount;
  std::string word;
  std::string star;
};

#endif

private의 변수들 설명

  • state : collectCount가 달라졌는지 확인하기 위한 변수. 만약 collectCount가 달라지지 않았다면 missCount를 증가시킨다.
  • collectCount : 임의의 word에서 총 몇개가 맞는 단어인지 count 합니다. 만약 word의 사이즈와 같아지면 게임을 종료합니다.
  • missCount : 게임을 진행하면서 몇 개를 틀렸는지 count 합니다. 게임이 끝나면 출력합니다.
  • word : 임의의 단어입니다. 객체가 생성될 때 입력되어집니다.
  • star : word의 size 만큼 *로 채운 string 변수입니다. 사용자가 문자를 맞출 때 마다 * 대신 해당 문자로 교체됩니다.

 

hangman.cpp

#include "hangman.h"

Hangman::Hangman(std::string& problemWord) {
  state = 0;
  collectCount = 0;
  missCount = 0;
  word = problemWord;
  star = std::string(word.size(), '*');
}

char Hangman::inputChar() {
  std::cout << "(Guess) Enter a letter in word " << star << " > ";
  char ch;
  std::cin >> ch;
  return ch;
}

bool Hangman::checkChStar(char ch) {
  for (int i = 0; i < star.size(); i++) {
    if (star[i] == ch) {
      std::cout << "\t" << ch << " is already in the word" << std::endl;
      return true;
    }
  }
  return false;
}

bool Hangman::checkStar() {
  if (collectCount != word.size()) return true;
  else {
    std::cout << "The word is " << word << ". You missed " << missCount << " time" << std::endl;
    return false;
  }
}

void Hangman::guessCh(char ch) {
  for (int i = 0; i < word.size(); i++) {
    if (word[i] == ch) {
      star.erase(i, 1);
      star.insert(i, 1, ch);
      collectCount++;
    }
  }
  if (state == collectCount) {
    std::cout << "\t" << ch << " is not in the word" << std::endl;
    missCount++;
  }
  else state = collectCount;
  return;
}

void Hangman::playHangman() {
  while (checkStar()) {
    char ch = inputChar();
    if (checkChStar(ch)) continue;
    guessCh(ch);
  }
  return;
}

 - Hangman 생성자 : 클래스 Hangman의 객체를 생성해주는 생성자. 임의의 string word를 입력받아서 word와 star의 값을 생성하며, state, collectCount, missCount를 초기화한다.

 - inputChar : 사용자로부터 문자 1개를 입력 받습니다.

 - checkChStar : 인수 ch가 star에 있는지 확인하며, 만약 있다면 이미 입력된 문자라고 출력하고 다시 입력을 받습니다.

 - checkStar : collectCount와 word의 사이즈를 확인해서 같다면 word와 missCount를 출력합니다.

 - 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을 입력하며 무한 루프문을 탈출하여 프로그램을 종료합니다.

아래는 해당 프로그램의 출력 결과입니다.

문제 10.15의 출력 결과

'Week4' 카테고리의 다른 글

Week 4 - 21.08.19  (0) 2021.08.19
Week 4 - 21.08.18  (0) 2021.08.18
Week 4 - 21.08.16  (0) 2021.08.17

C++ 공부 12일 차

 

오늘은 챕터 9의 class에 대한 공부를 했습니다.

 - 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() 함수를 호출하여 이들 수를 화면에 출력하는 테스트 프로그램을 작성하여라.
#include <iostream>

class EvenNumber {
public:
  EvenNumber() { value = 0; }
  EvenNumber(int num) { value = num; }

  int getValue() { return value; }
  bool isEven() { return (value % 2 == 0) ? true : false; }

  EvenNumber getNext() { return EvenNumber(value + 2); }
  EvenNumber getPrevious() { return EvenNumber(value - 2); }

private:
  int value;
};

위의 코드가 EvenNumber 클래스입니다.

public:

 - EvenNumber() : 인수가 없는 default 생성자. 기본적으로 0값을 value에 저장한다.

 - EvenNumber(int num) : 인수가 1개 있는 생성자. 입력받은 인수를 value에 저장한다.

 - int getValue() : value를 반환합니다.

 - bool isEven() : value가 짝수인지 확인합니다. 제가 추가로 넣었습니다.

 - EvenNumber getNext() : value의 다음 짝수를 EvenNumber 객체로 반환합니다.

 - EvenNUmber getPrevious() : value의 이전 짝수를 EvenNumber 객체로 반환합니다.

 

private:

 - int value : 객체에 저장된 정수 값을 표시하는 int 형의 변수

int main() {
  std::cout << "Enter Number: ";
  int number;
  std::cin >> number;
  EvenNumber even = EvenNumber(number);
  if (even.isEven()) {
    std::cout << "Current Number: " << even.getValue() << std::endl
      << "Next EvenNumber: " << even.getNext().getValue() << std::endl
      << "Previous EvenNumber: " << even.getPrevious().getValue() << std::endl;
  }
  else {
    std::cout << "The number is not even." << std::endl;
  }

  return 0;
}

위의 코드는 main 함수의 코드입니다.

사용자로부터 number를 입력받은 후, EvenNumber 객체 even를 생성합니다.

객체 even의 value가 짝수인지 확인하여 짝수이면 even의 현재 value 값, value의 다음 짝수와 이전 짝수를 출력합니다.

만약 even의 value가 홀수라면 "The number is not even."를 출력하고 프로그램을 종료합니다.

아래는 해당 프로그램의 출력 결과입니다.

문제 9.11의 출력 결과

 

'Week4' 카테고리의 다른 글

Week 4 - 21.08.19  (0) 2021.08.19
Week 4 - 21.08.18  (0) 2021.08.18
Week 4 - 21.08.17  (0) 2021.08.18

+ Recent posts