
Zombie 클래스를 구현하십시오.
- private 멤버: string
name- 멤버함수:
void announce(void);
Zombie가 자신을 다음과 같이 소개합니다:<name>: BraiiiiiinnnzzzZ...
- 추가로 다음 두가지 함수를 구현하십시오.
Zombie* newZombie(std::string name);:
name이름으로 Zombie 인스턴스를 생성하여, 함수 스코프 외부에서도 쓸 수 있게 반환합니다.void randomChump(std::string name);:
name이름으로 Zombie 인스턴스를 생성하고,announce()를 실행합니다.
- 디버깅을 위해 소멸자에 적절한 출력 메시지를 구현하십시오.

stack 영역:
.연산자를 통해 인스턴스에 접근heap 영역:
->연산자를 통해 인스턴스에 접근malloc, calloc으로 할당, free로 해제new로 할당, delete로 해제Zombie.hpp
#ifndef ZOMBIE_HPP
# define ZOMBIE_HPP
#include <iostream>
#include <string>
class Zombie{
public:
Zombie(std::string name);
~Zombie();
void announce(void);
private:
std::string name;
};
Zombie* newZombie(std::string name);
void randomChump(std::string name);
#endif
Zombie.cpp
#include "Zombie.hpp"
Zombie::Zombie(std::string name){
this->name = name;
}
Zombie::~Zombie(){
std::cout << this->name << " has been destroyed" << std::endl;
}
void Zombie::announce(){
std::cout << this->name << ": BraiiiiiiinnnzzzZ..." << std::endl;
}
newZombie.cpp
#include "Zombie.hpp"
Zombie *newZombie(std::string name){
Zombie *new_zombie;
new_zombie = new Zombie(name);
return (new_zombie);
}
randomChump.cpp
#include "Zombie.hpp"
void randomChump(std::string name){
Zombie Chump(name);
Chump.announce();
}
newZombie함수는 Zombie 인스턴스를 힙에 선언하여 함수 스코프 외부에서도 쓸 수 있게 반환하고, randomChump함수는 스택에 선언하여 announce()만 실행하고 소멸된다.main.cpp
#include "Zombie.hpp"
int main(void){
Zombie *new_zombie;
randomChump("Bob");
std::cout << std::endl;
new_zombie = newZombie("Alice");
new_zombie->announce();
delete new_zombie;
return (0);
}
randomChump 실행 후 바로 소멸자 메시지가 출력되는것을 확인할 수 있다.Zombie 떼거리를 구현하십시오.
- 다음 함수를 구현해야 합니다.
Zombie* zombieHorde(int N, std::string name);N개의 Zombie 오브젝트를 한번의 동작으로 할당해야하며, 매개변수로 주어진
name으로 이름을 각각 초기화합니다.
- 테스트 케이스를 구현해보고, 각각
announce()를 실행해봅니다.delete로 모두 할당을 해제하고 메모리 누수를 방지하는것을 잊지 마세요.
Zombie.hpp
#ifndef ZOMBIE_HPP
# define ZOMBIE_HPP
#include <iostream>
#include <string>
class Zombie{
public:
Zombie();
Zombie(std::string name);
~Zombie();
void announce(void);
void set_name(std::string name);
private:
std::string name;
};
Zombie* zombieHorde(int N, std::string name);
#endif
zombieHorde.cpp
#include "Zombie.hpp"
Zombie *zombieHorde(int N, std::string name){
Zombie* horde = new Zombie[N];
for (int i = 0; i < N; i++){
horde[i].set_name(name);
}
return (horde);
}
name 초기화가 불가능하므로, 디폴트 생성자를 넣어주었다.Zombie의 name 변수는 private이므로 setter함수도 만들어주었다.string 변수 "HI THIS IS BRAIN" 을 선언합니다.
변수의 포인터 stringPTR를 선언합니다.
변수의 레퍼런스 stringREF를 선언합니다.
- 순서대로 각각의 메모리 주소와, 다음으로 각각의 value를 출력하는 프로그램을 작성하세요.
#include <iostream>
#include <string>
int main(void){
std::string brain = "HI THIS IS BRAIN";
std::string* stringPTR = &brain;
std::string& stringREF = brain;
std::cout << "Printing memory addresses..." << std::endl;
std::cout << "string variable: " << &brain << std::endl;
std::cout << "string pointer: " << stringPTR << std::endl;
std::cout << "string reference: " << &stringREF << std::endl;
std::cout << std::endl;
std::cout << "Printing string values..." << std::endl;
std::cout << "string: " << brain << std::endl;
std::cout << "pointer: " << *stringPTR << std::endl;
std::cout << "reference: " << stringREF << std::endl;
}
reference에 대해 알아보라는 예제다.1. Weapon 클래스를 구현하십시오.
- private 멤버: string
type- 멤버함수:
getType() -type의 const reference를 반환한다.
setType(...) - 인자로 받은 string으로type을 설정한다.
2. HumanA, HumanB 클래스를 구현하십시오.
Weapon과name을 가집니다.- 멤버함수 attack(): 다음 형식의 문구를 출력
<name> attacks with their <weapon type>
- HumanA는 생성자에
Weapon을 가지지만, HumanB는 가지지 않습니다.- HumanB는
Weapon을 항상 지니지 않아도 되지만, HumanA는 항상 무장상태이어야 합니다.
다음 코드가 정상적으로 작동하는지 테스트해보세요.
두 케이스에 대해서 각각 첫번째attack()실행 시 "crude spiked club" 으로, 두번째 실행 시 "some other type of club" 으로 출력되어야 합니다.
int main()
{
Weapon club = Weapon("crude spiked club");
HumanA bob("Bob", club);
bob.attack();
club.setType("some other type of club");
bob.attack();
}
{
Weapon club = Weapon("crude spiked club");
HumanB jim("Jim");
jim.setWeapon(club);
jim.attack();
club.setType("some other type of club");
jim.attack();
}
return 0;
}
Weapon을 포인터로 전달할지, 레퍼런스로 전달할지 판단하는게 핵심인 예제다.setType()후, 별도의 setWeapon없이 공격의 출력 결과가 바뀌어야 한다는 것을 확인할 수 있다. 따라서 Weapon은 포인터 또는 레퍼런스의 형식으로 Human에게 전달되어야 한다.club이 포인터 변수로 선언되지 않은 점, HumanA 선언 시 객체 자체가 매개변수로 전달된다는 점에서 레퍼런스 임을 알 수 있다.HumanB는 Weapon을 항상 지니지 않아도 된다는 점에서 NULL 초기화 개념임을 추측할 수 있다. 따라서 HumanB는 포인터로, HumanA는 레퍼런스로 지니게 하여 적절히 구현한다.Weapon.hpp
#ifndef WEAPON_HPP
# define WEAPON_HPP
#include <iostream>
#include <string>
class Weapon{
public:
Weapon(std::string type);
~Weapon();
std::string const &getType() const;
void setType(std::string type);
private:
std::string type;
};
#endif
Weapon.cpp
#include "Weapon.hpp"
Weapon::Weapon(std::string type){
this->type = type;
}
Weapon::~Weapon() {}
std::string const &Weapon::getType() const{
return (this->type);
}
void Weapon::setType(std::string type){
this->type = type;
}
HumanA.hpp
#ifndef HUMANA_HPP
# define HUMANA_HPP
#include "Weapon.hpp"
class HumanA{
public:
HumanA(std::string name, Weapon &weapon);
~HumanA();
void attack();
private:
std::string name;
Weapon &weapon;
};
#endif
HumanA.cpp
#include "HumanA.hpp"
HumanA::HumanA(std::string name, Weapon &weapon) : name(name), weapon(weapon){}
HumanA::~HumanA() {}
void HumanA::attack(){
std::cout << this->name << " attacks with their " << this->weapon.getType() << std::endl;
}
HumanB.hpp
#ifndef HUMANB_HPP
# define HUMANB_HPP
#include "Weapon.hpp"
class HumanB{
public:
HumanB(std::string name);
~HumanB();
void setWeapon(Weapon &weapon);
void attack();
private:
std::string name;
Weapon *weapon;
};
#endif
HumanB.cpp
#include "HumanB.hpp"
HumanB::HumanB(std::string name){
this->name = name;
}
HumanB::~HumanB(){}
void HumanB::setWeapon(Weapon &weapon){
this->weapon = &weapon;
}
void HumanB::attack(){
std::cout << this->name << " attacks with their " << this->weapon->getType() << std::endl;
}
HumanAWeapon을 레퍼런스로 지니며, 생성 단계에서 초기화하여 지녀야 한다. 따라서 선언과 동시에 초기화를 해야하기 때문에, 초기화 리스트라는 방식으로 생성자를 구현한다.HumanA::HumanA(std::string name, Weapon &weapon) : name(name), weapon(weapon){} HumanBWeapon을 포인터로 지니며, 생성자와 함께 주어지지 않기 때문에 따로 setWeapon을 구현하여 "장착" 한다.filename과 두개의 문자열 s1, s2를 인자로 받는 프로그램을 작성하세요.
파일을 열고, 모든 s1을 찾아 s2로 대체하여 새로운 파일에 저장합니다. C 파일 관리 함수는 사용할 수 없으며,replace를 제외하고std::string클래스의 모든 멤버함수를 사용할 수 있습니다. 가능한 에러를 적절히 처리하고, 테스트 케이스를 만들어 함께 제출하세요.
sed를 재구현하는 과제이다. 이번 과제를 통해 C++에서 파일 입출력, std::string 클래스의 멤버함수에 대해 다루게 된다.main.cpp
#include <iostream>
#include <fstream>
#include <string>
int replace_string(std::string &str, const std::string &old_str, const std::string &new_str) {
size_t pos = 0;
size_t reps = 0;
while ((pos = str.find(old_str, pos)) != std::string::npos) {
str.erase(pos, old_str.length());
str.insert(pos, new_str);
pos += new_str.length();
reps++;
}
return (reps);
}
int main(int argc, char **argv) {
if (argc != 3 || (std::string)argv[2] == (std::string)argv[3]\
|| strlen(argv[2]) == 0) {
std::cerr << "Error: Invalid parameters" << std::endl;
return 1;
}
std::string filename = argv[1];
std::string s1 = argv[2];
std::string s2 = argv[3];
std::ifstream infile(filename);
if (infile.fail()) {
std::cerr << "Error: could not open file \"" << filename << "\"" << std::endl;
return 1;
}
std::string content;
std::string line;
while (std::getline(infile, line)){
content += line + '\n';
}
infile.close();
if (!replace_string(content, s1, s2)){
std::cerr << "Error: Cannot find \"" << s1 << "\" in \"" << filename << "\"" << std::endl;
return (0);
}
std::string extension = "";
size_t extension_pos = filename.find_last_of('.');
if (extension_pos != std::string::npos) {
extension = filename.substr(extension_pos);
filename = filename.substr(0, strlen(filename.c_str()) - strlen(extension.c_str()));
}
std::ofstream outfile((filename + "_replace" + extension));
if (outfile.fail()) {
std::cerr << "Error: could not create file \"" << filename << ".replace\"" << std::endl;
return 1;
}
outfile << content;
outfile.close();
return 0;
}
fstream헤더의 ifstream, ofstream 클래스를 통해 FILE 구조체 정보를 객체에 저장한다.std::ifstream infile(filename);open()을 해주지 않아도 파일 스트림 정보를 받아온다.main() 흐름:ifstream을 통해 파일을 열고, getline을 통해 파일의 내용을 string content에 개행을 포함하여 한줄로 받아온다.std::string 멤버 함수
size_t find(const string& str, size_t pos) const;
:인덱스pos부터 탐색하여str의 위치를 반환한다.
string& erase(size_t pos, size_t len);
:인덱스pos부터len만큼의 문자를 삭제하고, 문자열의 길이를 줄인다.
string& insert(size_t pos, const string& str);
:인덱스pos에서 시작하여str을 삽입한다.
replace_string을 통해 문자열 대체 횟수를 세어 반환하고, 0번이면 file에 s1이 없다는 뜻이므로 이때 또한 적절한 에러를 출력한다.
<<,>> 연산을 통해 직접 입출력을 전달하는 것도 가능하다. 대체가 완료되었으면 content를 outfile에 덮어쓰고, 적절히 close()해준다.Harl 클래스를 구현하십시오.
- private 멤버함수:
- void debug(void);
- void info(void);
- void warning(void);
- void error(void);- public 멤버함수:
- void complain(std::string level);
인자로 받은 level에 따라 반드시 함수 포인터를 사용하여 각각의 private멤버함수를 호출해야합니다. 구현 시 if/else if/else 문을 사용해서는 안됩니다.
Harl.hpp
#ifndef HARL_HPP
# define HARL_HPP
#include <iostream>
#include <string>
class Harl{
public:
Harl();
~Harl();
void complain(std::string level);
private:
void debug();
void info();
void warning();
void error();
};
#endif
Harl.cpp
#include "Harl.hpp"
Harl::Harl() {}
Harl::~Harl() {}
void Harl::complain(std::string level) {
int flag = 0;
std::string levels[4] = {"DEBUG", "INFO", "WARNING", "ERROR"};
void (Harl::*ptrs[4])(void) = {&Harl::debug, &Harl::info, &Harl::warning, &Harl::error};
for (int i = 0; i < 4; i++) {
if (level == levels[i]) {
(this->*ptrs[i])();
flag = 1;
}
}
if (flag == 0) {
std::cout << "Unknown level" << std::endl;
}
}
void Harl::debug(){
std::cout << "I love having extra bacon for my 7XL-double-cheese-triple-pickle-special-ketchup burger. I really do!" << std::endl;
}
void Harl::info(){
std::cout << "I cannot believe adding extra bacon costs more money. You didn't put enough bacon in my burger! If you did, I wouldn't be asking for more!" << std::endl;
}
void Harl::warning(){
std::cout << "I think I deserve to have some extra bacon for free. I've been coming for years whereas you started working here since last month." << std::endl;
}
void Harl::error(){
std::cout << "This is unacceptable! I want to speak to the manager now." << std::endl;
}
level에 맞는 멤버 함수를 for문으로 찾아 호출하는 방식으로 구현하였다. 각 출력 메시지는 pdf에 주어진 문구를 그대로 활용하였다. main()문에서는 무효한 level을 포함하여 한번씩 호출해보고 끝냈다.ex05 에서 구현한 Harl 클래스를 활용하여, 이번에는 "DEBUG", "INFO", "WARNING", "ERROR" 중 하나를 인자로 받아, 해당 레벨 이상의 모든 메시지를 출력하는 프로그램을 작성하세요.
switch문을 적절히 사용하면 보다 편리합니다.
Harl.cpp
#include "Harl.hpp"
Harl::Harl() {}
Harl::~Harl() {}
void Harl::complain(std::string level) {
int flag = 0;
std::string levels[4] = {"DEBUG", "INFO", "WARNING", "ERROR"};
void (Harl::*ptrs[4])(void) = {&Harl::debug, &Harl::info, &Harl::warning, &Harl::error};
for (int j = 0; j < 4; j++) {
if (levels[j] == level) {
flag = 1;
switch(j) {
case 0:
(this->*ptrs[0])();
case 1:
(this->*ptrs[1])();
case 2:
(this->*ptrs[2])();
case 3:
(this->*ptrs[3])();
}
break;
}
}
if (flag == 0) {
std::cout << "[ Probably complaining about insignificant problems ]" << std::endl;
}
}
void Harl::debug(){
std::cout << "I love having extra bacon for my 7XL-double-cheese-triple-pickle-special-ketchup burger. I really do!" << std::endl;
}
void Harl::info(){
std::cout << "I cannot believe adding extra bacon costs more money. You didn't put enough bacon in my burger! If you did, I wouldn't be asking for more!" << std::endl;
}
void Harl::warning(){
std::cout << "I think I deserve to have some extra bacon for free. I've been coming for years whereas you started working here since last month." << std::endl;
}
void Harl::error(){
std::cout << "This is unacceptable! I want to speak to the manager now." << std::endl;
}
complain부분만 살짝 바꿔주었다. 무효한 인자에 대해서는 지정한 문구를 출력해야한다.main.cpp
#include "Harl.hpp"
int main(int argc, char **argv){
if (argc != 2){
std::cerr << "Usage: ./Harl_2.0 [LEVEL]" << std::endl;
return (1);
}
Harl harl;
harl.complain(argv[1]);
return (0);
}