[C++]CPP Module 01

J_JEON·2022년 11월 16일
0

CPP

목록 보기
2/9

CPP module 01

ex00

  • 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();	
}

ex01

  • 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배열을 한번에 반환
}

ex02

  • 일반변수, 포인터변수, 레퍼런스변수를 사용해보고 차이점을 확인해보는 과제
  • "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" 출력
}

ex03

  • 포인터변수와 레퍼런스변수를 어떤 상황에서 사용해야할지를 실습해보는 과제
  • 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;
}
// 일반적인 생성자

ex04

  • 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);
}

ex05

  • 멤버함수에 대한 포인터를 사용해보는 과제
  • 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);
}

ex06

  • 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;
	}
}
profile
늅늅

0개의 댓글