- Zombie 클래스를 생성하고 해당 클래스를 heap영역과 stack영역에 할당해보고 차이를 실습해보는 과제
- announce()는 문자열을 출력, randomchump()는 함수 내에서 좀비클래스를 생성, newZombie()는 new를 사용하여 Zombie클래스의 메모리를 할당하고 반환
class Zombie { private: std::string name; public: Zombie(); // 생성자 Zombie(std::string); // string을 인자로 받는 생성자 void announce(void); ~Zombie(); // 소멸자 }; Zombie::Zombie() { } Zombie::Zombie(std::string sname) { name = sname; } void Zombie::announce(void) { std::cout << name << ": BraiiiiiiinnnzzzZ..." << std::endl; } Zombie::~Zombie() { std::cout << name << " is dead..." << std::endl; } Zombie *newZombie(std::string sname) { Zombie *newzom = new Zombie(sname); return (newzom); // 할당한 Zombie를 반환, 사용이 끝나면 delete 해줘야 누수 X } void randomChump(std::string sname) { Zombie zom(sname); // 함수종료시 자동으로 소멸자 호출됨 zom.announce(); }
- 00에서 만든 클래스를 클래스배열로 생성해보는 과제
- N개의 Zombie클래스를 한번에 할당하고 한번에 반환해주어야 함
Zombie* zombieHorde(int N, std::string name) { std::string name_num = "0"; Zombie *zombie_horde = new Zombie[N]; // N개의 Zombie를 new로 동적할당 for (int i = 0; i < N ; i++) { zombie_horde[i].set_name(name + name_num); // 각 Class내의 Name을 설정 // string이기에 + 로 문자열을 합칠 수 있음 name_num[0]++; std::cout << zombie_horde[i].get_name() << " is wakeup" << std::endl; } return (zombie_horde); // 첫 Zombie의 포인터를 반환 } int main(void) { Zombie *zom_horde = zombieHorde(5, "zom"); for (int i = 0 ; i < 5 ; i++) { zom_horde[i].announce(); } delete[] (zom_horde); // delete[]를 사용해 Class배열을 한번에 반환 }
- 일반변수, 포인터변수, 레퍼런스변수를 사용해보고 차이점을 확인해보는 과제
- "HI THIS IS BRAIN" 이라는 내용물을 담은 문자열을 작성 후 문자열의 주소를 담은 stringPTR 을 생성. 그리고 문자열의 참조를 담은 stringREF 생성.
- stringREF는 NULL일 수 없으며, stringREF의 값을 변경시 A의 값 역시 변경됨
int main() { std::string A = "HI THIS IS BRAIN"; // 문자열을 담은 A변수 std::string *stringPTR = &A; // A변수의 주소를 값으로 가지고있는 포인터변수 std::string &stringREF = A; // A변수와 같은 메모리를 참조하고있는 레퍼런스 변수 std::cout << &A << std::endl; // A의 주소가 출력 std::cout << stringPTR << std::endl; // A의 주소가 출력 std::cout << &stringREF << std::endl; // A의 주소가 출력 std::cout << "------------------------------" << std::endl; std::cout << A << std::endl; // "HI THIS IS BRAIN" 출력 std::cout << *stringPTR << std::endl; // "HI THIS IS BRAIN" 출력 std::cout << stringREF << std::endl; // "HI THIS IS BRAIN" 출력 }
- 포인터변수와 레퍼런스변수를 어떤 상황에서 사용해야할지를 실습해보는 과제
- Weapon 클래스를 만들고 문자열 자료형과, 해당 문자열의 상수 참조를 반환하는 getType메소드를 포함해야 함, 당연히 setType도 있어야 함
- HumanA와 HumanB라는 두 개의 클래스를 만들고, 두 클래스 모두 Weapon과 이름, 다음과 같은 문자열을 출력하는 attack() 함수를 포함해야 함 "(NAME) attacks with his (WEAPON_TYPE)"
- HumanA는 생성자에서 Weapon을 지니지만, HumanB는 그렇지 않음, HumanB는 Weapon이 없을 수도 있지만, HumanA는 항상 무장한 상태
class Weapon { private: std::string type; public: Weapon(std::string type); std::string getType() const; void setType(std::string newtype); ~Weapon(); }; class HumanA { private: std::string name; Weapon &weapon; // HumanA의 weapon은 NULL일 수 없고 외부에서 변경해야하기에 ref변수로 사용 public: HumanA(std::string name, Weapon &weapon); // 참조변수를 초기화하는 생성자에서는 일반적인방법이 아닌 초기화리스트를 사용해야함 void attack(); void setWeapon(Weapon &newweapon); ~HumanA(); }; class HumanB { private: std::string name; Weapon *weapon; // HumanB의 weapon은 NULL일 수 있고 외부에서 변경해야하기에 ptr변수로 사용 public: HumanB(std::string name); HumanB(std::string name, Weapon &weapon); void attack(); void setWeapon(Weapon &newweapon); ~HumanB(); }; HumanA::HumanA(std::string name, Weapon &weapon) : name(name), weapon(weapon) { } // 초기화리스트를 사용한 생성자 HumanB::HumanB(std::string name) { this->name = name; } // 일반적인 생성자
- replace란 이름의 프로그램을 작성. 프로그램은 파일명과 두 개의 문자열 s1, s2를 인자로 받아야 하며 문자열은 비어 있으면 안 됩니다.
- 프로그램은 파일을 열고, 파일 내의 모든 s1을 s2로 대체한 후에 결과물을 FILENAME.replace에 저장해야 함.
- replace를 제외한 모든 std::string 클래스의 멤버 함수들을 사용 가능
int main(int argc, char **argv) { std::string filename; std::string str; std::string savestr; std::ifstream readfile; std::ofstream writefile; std::string::size_type n; if (check_arg(argc, argv)) // argv가 3개인지, 맞는 형식인지 확인 return(1); filename = argv[1]; readfile.open(filename); // 파일을 open함 if (readfile.fail()) // 실패시 에러 { std::cout << "can't open file \""<< filename << "\"" << std::endl; return (1); } while(!readfile.eof()) // 파일의 끝을 읽을때까지 반복 { std::getline(readfile, savestr); // 한줄씩 불러와 savestr에 저장 str = str + savestr; // string이기때문에 +로 합치기 가능 if(!readfile.eof()) // 끝까지 읽었다면 줄바꿈 하나 추가 str = str + "\n"; } readfile.close(); // open한 파일을 close해줌 writefile.open((filename + ".replace")); // 새로운 파일인 filename.replace를 만들고 내용을 쓰기위해 open if (writefile.fail()) // 실패시 에러 { std::cout << "can't make file \""<< filename + ".replace" << "\"" << std::endl; return (1); } while(1) { n = str.find(argv[2]); //문자열내에서 s1문자열을 찾음 if (n == std::string::npos) // 찾지못했다면 반복문 종료 break; else { savestr = argv[3] + str.substr(((int)n + check_len(argv[2])) , str.length()); // s2문자열 + s1문자열이 시작된 부분부터 끝까지를 합쳐서 하나의 문자열 생성 str = str.substr(0, (int)n); // 기존 문자열의 시작부터 s1이 시작된부분까지 하나의 문자열 생성 str = str + savestr; // 두개를 합쳐줌 } } writefile.write(str.c_str(), str.length()); // 생성한 파일에 만든 문자열을 입력 writefile.close(); // open한 파일을 close return (0); }
- 멤버함수에 대한 포인터를 사용해보는 과제
- if -> if else -> else처럼 복잡해지는 if문을 사용하지않아야 함
- 문자열 DEBUG, INFO, WARNING, ERROR를 넘겨주고 해당하는 함수를 실행시켜줘야함
# define DEBUG 0 # define INFO 1 # define WARNING 2 # define ERROR 3 # define TOTAL_NUM_OF_LEVEL 4 class Harl { private: void debug(void); void info(void); void warning(void); void error(void); public: Harl(); void complain(std::string level); ~Harl(); }; void Harl::complain(std::string level) { std::string levels[4] = {"DEBUG", "INFO", "WARNING", "ERROR"}; void (Harl::*fnptr[4])(void) = {&Harl::debug, &Harl::info, &Harl::warning, &Harl::error}; // 함수 포인터 배열을 생성하고 함수들을 할당해줌 for(int i = 0 ; i < 4 ; i++) { if (level == levels[i]) // 문자열로 받아온 level과 비교 문자열들을 저장해둔 levels[]를 비교했을때 동일한것이 나온다면 (this->*fnptr[i])(); // 해당하는 번호의 함수를 실행 } } int main() { Harl h; h.complain("DEBUG"); h.complain("INFO"); h.complain("WARNING"); h.complain("ERROR"); return (0); }
- 05에서 만든것을 응용해 잘못된 인자가 들어온다면 특정메시지를, 맞는 인자가 들어온다면 해당레벨 ~ 상위레벨까지 함수를 순서대로 실행시키도록 해야함
- karenFilter 라는 프로그램을 작성. 해당 프로그램은 인자값으로 확인하고 싶은 로그 레벨을 받으며, 해당 레벨 또는 그 이상의 레벨에 대한 모든 정보를 출력. 아래는 예시
$> ./karenFilter "WARNING"
[ WARNING ]
I think I deserve to have some extra bacon for free.
I’ve been coming here for years an you just started working here last month.[ ERROR ]
This is unacceptable, I want to speak to the manager now.$> ./karenFilter "I am not sure how tired I am today..."
[ Probably complaining about insignificant problems ]void Harl::complain(std::string level) { int i; std::string levels[4] = {"DEBUG", "INFO", "WARNING", "ERROR"}; for(i = 0 ; i < 4 ; i++) { if (level == levels[i]) break; } switch (i) // switch case를 사용해 필터링, 또한 각 case에서 탈출하지않고 상위레벨의 함수도 실행할 수 있도록 함 { case 0: this->debug(); case 1: this->info(); case 2: this->warning(); case 3: this->error(); break; default: // 아무것도 해당하지않을때 실행 std::cout << "[ Probably complaining about insignificant problems ]" << std::endl; } }