42 Seoul

[42Seoul] CPP 01

jaewpark 2022. 7. 11. 09:57

General rules ▼

더보기
General rules
클래스 이름을 UpperCamelCase 형식으로 작성합니다. 클래스 코드가 포함된 파일은 항상 클래스 이름에 따라 이름이 지정됩니다.
예를 들어: ClassName.hpp/ClassName.h, ClassName.cpp 또는 ClassName.tpp입니다. 그런 다음, 벽돌 벽을 나타내는 "BrickWall" 클래스의 정의가 들어 있는 헤더 파일이 있는 경우, 그 이름은 BrickWall.hpp가 됩니다.
▶ 달리 지정하지 않는 한 모든 출력 메시지는 줄 바꿈 문자로 끝나야 하며 표준 출력에 표시되어야 합니다.
▶ 달리 명시되지 않는 한 네임스페이스 키워드 사용 <ns_name> 및 friend 키워드는 금지됩니다. 
▶ C++에서도 메모리 누수가 발생합니다. 새 키워드를 사용하여 메모리를 할당할 때 메모리 누출을 방지해야 합니다.
▶ 모듈 02부터 모듈 08까지, 당신의 수업은 특별히 달리 명시되지 않은 경우를 제외하고 정교회 정식 형식으로 설계되어야 한다.
▶ 헤더 파일에 함수의 선언이 아닌 구현은 금지된다.
▶ include gards를 사용해야 합니다.
Include 가드 는 포함된 횟수에 상관없이 컴파일러가 이 파일을 한 번만 처리하도록 합니다. Include 가드는 파일이 한 번만 포함되도록 보장하는 일련의 전처리기 지시문입니다.
사용된 전처리기:
#ifndef : 정의되지 않은 경우 제공된 매크로가 존재하지 않는지 확인합니다.
#define : 매크로를 정의합니다.
#endif : #ifndef 지시문 을 닫습니다 .

Exercise 00 : BraiiiiiiinnnzzzZ

좀비 클래스에
void announce (void);
<name> : BraiiiiiiinnnzzzZ...

다음과 같은 메시지를 출력해야 합니다. (< 그리고 > 는 출력 금지)
Zombie* newZombie( std::string name );
좀비를 만들고 이름을 붙인 다음 그것을 돌려주므로 당신은 그것을 기능 범위 밖에서 사용할 수 있다.
void randomChump( std::string name );

좀비를 만들고, 이름을 붙이고, 좀비가 자신을 알린다.

좀비는 더 이상 필요하지 않을 때 없애야 한다. 디버깅을 위해 소멸자는 좀비의 이름이 포함된 메시지를 인쇄해야 합니다.


new Zombie를 생성 전 알아야 두어야 할 것

또다시 돌아온 스택과 힙

프로그램이 사용하는 메모리는 일반적으로 segment라고 하는 몇 가지 영역으로 나뉜다.

code, data, heap 그리고 stack

 

Heap segment는 동적 메모리 할당에 사용되는 메모리를 추적, C++에서 new 연산자를 사용해서 메모리를 할당하면 이 메모리는 Heap segment에 할당됩니다. 이 메모리의 주소는 연산자 new에 의 해 포인터에 저장될 수 있다. (메모리 요청이 순차적으로 할당이 안될 수도 있다) 동적으로 할당된 변수가 삭제되면 메모리는 힙으로 반환되고, 이후 다시 할당될 수 있다. 포인터를 삭제하면 변수가 삭제되는 것이 아니라 관련 주소의 메모리를 운영체제에 반환하는 것이다.

  • 힙에 메모리를 할당하는 것은 비교적 느리다.
  • 할당된 메모리는 명시적으로 할당 해제하거나 응용 프로그램이 종료될 때까지 유지된다. (메모리 릭 주의)
    (delete 사용으로 소멸차 호출, 메모리 해제)
  • 동적으로 할당된 메모리는 포인터를 통해 접근한다: 포인터를 역참조하는 것은 변수에 직접 접근하는 것보다 느리다.
  • 힙은 큰 메모리 풀이므로 큰 배열, 구조체 또는 클래스를 할당할 수 있다.

Stack segment는 main() 함수로부터 현재 실행 지점까지의 모든 활성 함수를 추적하고 모든 함수 매개 변수와 지역 변수의 할당을 처리한다.

  • 스택에 메모리를 할당하는 것은 비교적 빠르다
  • 스택에 할당된 메모리는 스택 범위에 있을 때만 접근할 수 있다
  • 스택에 할당된 모든 메모리는 컴파일 타임에 알려진다. 메모리 변수를 통해 직접 접근할 수 있다
  • 스택은 비교적 크기가 작으므로 스택 공간을 많이 차지하는 지역 변수를 만드는 것은 좋지 않다

 

Class 생성자 : 참고

initializer list로 클래스 맴버를 초기화할 수 있습니다.

Box(int width, int length, int height)
        : m_width(width), m_length(length), m_height(height)
    {}

explicit 모든 매개 변수에서 기본값을 사용하는 경우 이 매개 변수 형식은 클래스 형식으로 암시적으로 변환할 수 있다.

경우에 따라 이러한 변환은 유용할 수 있지만 코드에서 미세하지만 심각한 오류를 발생시키는 경우가 더 자주 있습니다. 일반적으로 이러한 종류의 암시적 형식 변환을 방지하려면 생성자(및 사용자 정의 연산자)에서 키워드를 사용해야 합니다.

explicit Box(int size): m_width(size), m_length(size), m_height(size){}
class Box {
    public:
    	Box() {}
        explicit Box(int i) : w(i), h(i) {} // 명시적 생성자
        Box(int width, int height) : w(width), h(height) {}
	private:
    	// 기본 생성자를 호출할 때 값이 0이 됩니다.
    	int w{ 0 };
        int h{ 0 };
};

 

Class 소멸자 : 참고

소멸자가란 개체가 범위를 벗어나거나 호출에 의해 명시적으로 제거될 때 자동으로 호출 delete되는 멤버 함수

 


Exercise 01 : Moar brainz!

Zombie* zombieHorde( int N, std::string name );
N 좀비 개체를 단일 할당에 할당해야 합니다. 그런 다음 좀비를 초기화하여 각 좀비에게 매개 변수로 전달된 이름을 부여, 첫 번째 좀비의 포인터를 반환

모든 좀비를 삭제하고 memory leaks을 확인

 


this 포인터 (참고)

class 포인터로, 멤버 함수가 호출되는 개체를 가르킵니다.

void Date::setMonth( int mn )
{
   month = mn;            // These three statements
   this->month = mn;      // are equivalent
   (*this).month = mn;
}
// 멤버 함수에서 현재 개체를 반환하기 위해 *this 식이 주로 사용
return *this;

// this 포인터는 자체 참조를 방지할 때도 사용
if (&Object != this) {
// do not execute in cases of self-reference
포인터는 this 수정할 수 없으므로 포인터에 this 대한 할당을 허용되지 않습니다

 

delete 연산자 (참고)

new 배열을 delete 비롯한 기본 제공 형식에도 연산자를 사용할 수 있습니다. 배열을 참조하는 경우 pointer 빈 대괄호([])를 다음 앞에 pointer배치

int* set = new int[100];
//use set[]
delete [] set;

 


Exercise 02 : HI THIS IS BRAIN


Exercise 03 : Unnecessary violence

Weapon class 구현

  • private attribute type은 string 
  • getType() type은 const reference
  • setType() type은 passed as parameter로 설정

 

HumanA와 HumanB 구현

  • Weapon과 Name 존재
  • attack의 형태는 <name> attacks with their <weapon type> 와 동일
  • HumanA가 생성자에 무기를 가지고 있는 반면, HumanB는 그렇지 않다
  • HumanB가 항상 무기를 가지고 있는 것은 아닐 수 있지만, HumanA는 항상 무기를 가지고 있을 것이다.

Reference (참고)

  • 참조(reference) 변수는 한 객체가 다른 객체를 연결하는 수단입니다.
  • 초기화되고 나면 다른 개체를 참조하도록 설정하거나 null로 설정할 수 없습니다.
  • 명명된 변수를 참조하는 lvalue 참조와 임시 개체를 참조하는 rvalue 참조의 두 가지 종류
    (The & operator signifies an lvalue reference and the && operator signifies either an rvalue reference, or a universal reference (either rvalue or lvalue) depending on the context)
// 자료형& 참조 변수명 = 변수명;
int main(void) {
  int number = 303;
  int& refer = number;
  
  // 변수 값
  std::cout << number << std::endl;
  std::cout << refer << std::endl;

  // 주소 값
  std::cout << &number << std::endl;
  std::cout << &refer << std::endl;
}
선언과 동시에 초기화
null 참조 불가
참조하려는 변수와 데이터 타입 일치
(const로 선언된 변수는 const, non-const는 non-const만 참조 가능)
재참조 불가능

Exercise 04 : Sed is for losers

파일 이름 및 s1,s2 세 가지 매개 변수를 사용하는 프로그램

  • C 파일 조작 기능 사용은 금지
  • std::string의 멤버 함수 가능(단, replace 제외)
  • 오류를 처리

파일 입출력 ifstream ofstream fstream

파일을 읽기만 한다면 ifstream, 파일을 쓰기만 한다면 ofstream, 읽고 쓰는 거 둘 다 한다면 fstream을 사용하면 됩니다.

ifstream(ofstream) 객체를 생성자를 통해 만들거나 open 메소드를 통해서 파일을 열 수 있습니다.

std::ifstream ifs;
ifs.open("read.txt");

std::ofstream ofs("write.txt");

그리고 파일이 제대로 열렸는지 확인하려면 fail() 함수로 확인할 수 있습니다.

 

ifs.open(file_name);
if (ifs.fail())
    std::cerr << file_name << " open failed" << std::endl;
while (!ifs.eof())
{
    std::string line;
    std::getline(ifs, line);
    std::cout << line << std::endl;
}
ifs.close();

while문에서 getline 으로 한 줄씩 읽다가 eof() 함수를 사용하여 EOF를 만날 때까지 반복하게 만듭니다.

std::cerr는 오류에 대한 표준 출력 스트림으로 un-itbuffered 로 동작한다.
un-itbuffered란 '이 연산은 buffered이기는 하지만 출력 이후 바로 버퍼를 비운다

 

try throw catch문

try에서 예외 처리로 throw하게 되면 catch문으로 빠져나와 동작을 하게 됩니다. 예외처리를 하기 위한 용도로 가독성과 유지 보수를 하는데 더 좋기 때문에 사용을 합니다.

try 블록은 예외 발생에 대한 검사의 범위를 지정할 때 사용하며,  catch 블록은 try 블록에서 발생한 예외를 처리하는 코드가 담기는 영역이고,throw는 예외상황에 대한 정보를 담은 의미 있는 데이터이어야만 합니다.

 

string::find 함수 (링크)

링크에서 제공된 예제를 보게 되면, find(찾고자 하는 문자열) 의 형태로 사용되고 반환값으로는 첫 번째 일치된 첫번째 문자의 index 입니다. 일치하는 항목이 없으면 이 함수는 string::npos 를 반환

두 번째 인자(int)를 넣게 되면 해당 index부터 찾습니다.

 

string::substr 함수 (링크)

string substr (size_t pos = 0, size_t len = npos) const;

인자를 1개만 넣으면 pos 부터 string 끝까지 자른 문자열을 반환합니다.

pos, npos 2개의 인자를 넣으면 사이에 해당하는 문자열을 반환합니다.

 

string&::erase 함수 (링크)

string& erase (size_t pos = 0, size_t len = npos);

인자를 1개만 넣으면 index(pos값)를  삭제합니다.

pos, npos 2개의 인자를 넣으면 사이에 해당하는 문자열을 삭제합니다.


Exercise 05 : Harl?

if/else if/else를 사용하지 않고 pointers to member functions 통해서 위의 네 개의 멤버 함수를 호출하는 퍼블릭 멤버 함수를 만들면 됩니다.

함수 포인터 (참고)

반환형 (*포인터 변수 이름) (함수의 매개변수)

맴버 함수 포인터 (참고)

/* 함수 포인터 선언 */
[반환타입]	(*[클래스명]::[멤버 함수 포인터명])([매개변수 목록]);

/* 함수 포인터에 함수를 할당. */
[멤버 함수 포인터명] = &[클래스명]::[멤버 함수명];

/* 함수 호출 */
// 클래스 내부에서 함수 호출
(this->*[멤버 함수 포인터명])([매개변수 목록]);

// 클래스 외부에서 함수 호출
[클래스명]	[인스턴스명] = [생성자];		// 인스턴스 생성
([인스턴스명].*[멤버 함수 포인터명])([매개변수 목록]);	// 인스턴스 생성 후, 인스턴스를 활용하여 함수 호출

 

참고 블로그 (여기)