cpp module 03

slee2·2021년 10월 10일
0

42Seoul

목록 보기
12/15
post-thumbnail

ex00

ClapTrap 클래스

  • Name(생성자의 매개변수)
  • Hitpoints (10)
  • Energy points (10)
  • Attack damage (0)
  • void attack(std::string const & target)
  • void takeDamage(unsigned int amount)
  • void beRepaired(unsigned int amount)

attack을 실행할때,
ClapTrap <name> attacks <target>, causing <damage> points of damage!

ClapTrap.cpp

#include "ClapTrap.hpp"

ClapTrap::ClapTrap() {
	this->Name = "default";
	std::cout << "ClapTrap_Name : " << this->Name << std::endl;
	this->Hitpoints = 10;
	this->energy = 10;
	this->damage = 0;
}

ClapTrap::ClapTrap(std::string name) {
	this->Name = name;
	std::cout << "ClapTrap_Name : " << this->Name << std::endl;
	this->Hitpoints = 10;
	this->energy = 10;
	this->damage = 0;
}

ClapTrap::~ClapTrap() {
	std::cout << "ClapTrap " << this->Name << " has been destroyed." << std::endl;
}

void	ClapTrap::attack(std::string const & target) {
	std::cout << "ClapTrap " << this->Name << \
		" attacks " << target << " , causing " \
		<< this->damage << " points of damage!" << std::endl;
}

void	ClapTrap::takeDamage(unsigned int amount) {
	if (this->energy <= amount) {
		std::cout << this->Name << " is dead" << std::endl;
		this->energy = 0;
	}
	else {
		this->energy -= amount;
		std::cout << "ClapTrap " << this->Name << \
			" take Damage " << amount << " , remaning hp is " \
			<< this->energy << std::endl;
	}
}

void	ClapTrap::beRepaired(unsigned int amount) {
	if (this->energy == 0) {
		std::cout << "ClapTrap " << this->Name << " is repaired by " << amount << " and comes back to life" << std::endl;
		this->energy += amount;
	}
	else {
		this->energy += amount;
		std::cout << "ClapTrap " << this->Name << " is repaired by " << amount << " and remaning hp is " << this->energy << std::endl;
	}
}

ClapTrap&	ClapTrap::operator=( ClapTrap const& clap) {
	this->Name = clap.Name;
	this->Hitpoints = clap.Hitpoints;
	this->energy = clap.energy;
	this->damage = clap.damage;
	std::cout << "ClapTrap "<< this->Name << " operator= is called" << std::endl;
	return *this;
}

ClapTrap.hpp

class ClapTrap {
	private:
		std::string	Name;
		unsigned int	Hitpoints;
		unsigned int energy;
		unsigned int damage;
	public:
		void	attack(std::string const & target);
		void	takeDamage(unsigned int amount);
		void	beRepaired(unsigned int amount);
		ClapTrap&	operator=( ClapTrap const& clap);
		ClapTrap(std::string name);
		ClapTrap();
		~ClapTrap();
};

ex01

ScavTrap 클래스

  • ClapTrap 속성을 사용함(ClapTrap을 수정해야함)
  • Name (Parameter of constructor)
  • Hitpoints (100)
  • Energy points (50)
  • attack damage (20)
  • void guardGate();

void guarGate()
게이트 키퍼 모드에 진입했음을 표준출력으로 알린다.

ScavTrap.hpp

#include "ClapTrap.hpp"

// ClapTrap을 상속받는다. public으로 받았으니 public보다
// 넓은 범위에 있는 것들은(없지만) 전부 public이 된다.
// (public보다 좁은 범위인 protected, pravte같은 것들은 그대로 상속받는다.)
class ScavTrap: public ClapTrap {
	public:
		ScavTrap();
		ScavTrap( std::string _name);
		~ScavTrap();
		void	attack(std::string const & target);
		void	takeDamage(unsigned int amount);
		void	beRepaired(unsigned int amount);
		void	guardGate();

		ScavTrap& operator=( ScavTrap const& scav);
};

생성자의 실행순서는
부모 -> 자손
소멸 순서는
자손 -> 부모

그러므로 예제에서의 순서는
ClapTrap 생성자 -> ScavTrap 생성자 -> ScavTrap 소멸자 -> ClapTrap 소멸자

ScavTrap.cpp

#include "ScavTrap.hpp"

// ClapTrap의 생성자를 실행시킨다.
ScavTrap::ScavTrap(): ClapTrap() {
	this->Hitpoints = 100;
	this->energy = 50;
	this->damage = 20;
	std::cout << "ScavTrap_Name : " << this->Name << std::endl;
}

ScavTrap::ScavTrap( std::string _name): ClapTrap(_name) {
	this->Hitpoints = 100;
	this->energy = 50;
	this->damage = 20;
	std::cout << "ScavTrap_Name : " << this->Name << std::endl;
}

ScavTrap::~ScavTrap() {
	std::cout << "ScavTrap "<< this->Name << " has been destroyed." << std::endl;
}

ScavTrap& ScavTrap::operator=( ScavTrap const& scav) {
	ClapTrap::operator=(scav);
	std::cout << "ScavTrap " << this->Name << " operator= is called" << std::endl;
	return *this;
}

void	ScavTrap::attack(std::string const & target) {
	std::cout << "ScavTrap " << this->Name << \
		" attacks " << target << " , causing " \
		<< this->damage << " points of damage!" << std::endl;
}

void	ScavTrap::takeDamage(unsigned int amount) {
	if (this->energy <= amount) {
		std::cout << this->Name << " is dead" << std::endl;
		this->energy = 0;
	}
	else {
		this->energy -= amount;
		std::cout << "ScavTrap " << this->Name << \
			" take Damage " << amount << " , remaning hp is " \
			<< this->energy << std::endl;
	}
}

void	ScavTrap::beRepaired(unsigned int amount) {
	if (this->energy == 0) {
		std::cout << "ScavTrap " << this->Name << " is repaired by " << amount << " and comes back to life" << std::endl;
		this->energy += amount;
	}
	else {
		this->energy += amount;
		std::cout << "ScavTrap " << this->Name << " is repaired by " << amount << " and remaning hp is " << this->energy << std::endl;
	}
}

void	ScavTrap::guardGate() {
	if (energy)
		std::cout << "ScavTrap " << this->Name << " has entered gate guard mode." << std::endl;
	else
		std::cout << "ScavTrap " << this->Name << " cannot enter gate guard mode because " << this->Name << " is dead." << std::endl;
}

ex02

FragTrap

  • ClapTrap의 속성을 사용
  • Name (Parameter of constructor)
  • Hitpoints (100)
  • Energy points (100)
  • attack damage (30)
  • void highFivesGuys(void)

void highFivesGuys(void)
긍정적인 하이파이브 요청을 표준출력으로 표현

FragTrap.hpp

class FragTrap : public ClapTrap {
	public:
		FragTrap();
		FragTrap( std::string name);
		~FragTrap();
		FragTrap&	operator=( FragTrap const& frag);
		void	highFivesGuys(void);
};

FragTrap.cpp

#include "FragTrap.hpp"

FragTrap::FragTrap(): ClapTrap() {
	this->Hitpoints = 100;
	this->energy = 100;
	this->damage = 30;
	std::cout << "FragTrap_Name : " << this->Name << std::endl;
}

FragTrap::FragTrap( std::string name): ClapTrap(name) {
	this->Hitpoints = 100;
	this->energy = 100;
	this->damage = 30;
	std::cout << "FragTrap_Name : " << this->Name << std::endl;
}

FragTrap::~FragTrap() {
	std::cout << "FragTrap " << this->Name << " has been destroyed." << std::endl;
}

FragTrap&	FragTrap::operator=( FragTrap const& frag) {
	ClapTrap::operator=(frag);
	std::cout << "FragTrap " << this->Name << " operator= is called" << std::endl;
	return *this;
}

void	FragTrap::highFivesGuys(void) {
	if(this->energy)
		std::cout << "FragTrap " << this->Name << " asks for a positive high-five" << std::endl;
	else
		std::cout << "FragTrap " << this->Name << " can't ask for a positive high-five because " << this->Name << " is dead" << std::endl;

}

ex03

DiamondTrap 클래스

  • ScavTrap과 FragTrap의 속성을 사용
  • Name (생성자의 매개변수)
  • Claptrap::Name (생성자의 매개변수 + "_clap_name")
  • Hitpoints (Fragtrap)
  • Energy points (Scavtrap)
  • Attack damage (Fragtrap)
  • attack (Scavtrap)
  • void whoAmI()

void whoAmI()
DiamondTrap 생성자의 이름과 ClapTrap 생성자의 이름을 호출하여 둘이 다른 이름이 초기화됐음을 보여준다.

다이아몬드 상속(다중 상속)

현재 ScavTrap 클래스와 FragTrap 클래스는 ClapTrap을 상속하고 있는 상태일 것이다. 여기서 DiamondTrap 클래스가 두개의 클래스를 상속한다면 위 그림처럼 다이아몬드 형태의 다중상속을 한다고 해서 다이아몬드 상속이라고 불린다.

위의 경우 문제가 하나 발생하는데 저런 식으로 상속을 할 경우,

컴파일러는 ScavTrap의 상속자인 ClapTrap과 FragTrap의 상속자인 ClapTrap 두개의 ClapTrap을 컴파일하게 된다.
그래서 ClapTrap생성자를 호출할때 어떤 ClapTrap인지 알 수 없게 되어 오류가 발생한다.(발생안할 수도 있긴한다. 그때는 생성자가 두번 호출된다.)

해결책
각 클래스를 선언할때

class ScavTrap: public virtual ClapTrap
class FragTrap: public virtual ClapTrap

위처럼 선언하면 된다. Virtual은 가상 상속이라고 불리는 것으로, 위의 경우 이전에는 ClapTrap 클래스를 상속받아 새로운 클래스를 생성했다면 Virtual을 붙인 후에는 ClapTrap 클래스가 있는 곳을 가르킨다. 라고 생각하면 된다. 그렇게 되면 중복되지 않기 때문에 겹칠 일이 없게 된다.

DiamondTrap.hpp


// 아래처럼 코드를 짜면 FragTrap -> ScavTrap 순서로 진행된다.
class DiamondTrap: public FragTrap, public ScavTrap {
	private:
		std::string Name;
	public:
		DiamondTrap();
		DiamondTrap( std::string n);
		~DiamondTrap();
		void	attack(std::string const & target);
		DiamondTrap&	operator=( DiamondTrap const& Diamond);
		void	whoAmI();
};

DiamondTrap.cpp

#include "DiamondTrap.hpp"

// ClapTrap -> FrapTrap -> ScavTrap 순서로 생성자 호출
// 소멸은 반대로 된다.
DiamondTrap::DiamondTrap(): ClapTrap(), FragTrap(), ScavTrap(), Name(ClapTrap::Name) {
// 이 경우 마지막에 ScavTrap 생성자 값으로 세팅되기 때문에 FragTrap 값을 설정하려는
// 속성은 수동으로 바꿔주는 모습을 확인할 수 있다.
	ClapTrap::Name += "_clap_name";
	ClapTrap::damage = 30;
	std::cout << "DiamondTrap_Name : " << this->Name << std::endl;
}

DiamondTrap::DiamondTrap(std::string n): ClapTrap(n), FragTrap(n), ScavTrap(n), Name(n) {
	ClapTrap::Name += "_clap_name";
	ClapTrap::damage = 30;
	std::cout << "DiamondTrap_Name : " << this->Name << std::endl;
}

DiamondTrap::~DiamondTrap() {
	std::cout << "DiamondTrap " << this->Name << " has been destroyed." << std::endl;
}

void	DiamondTrap::attack(std::string const & target) {
	ScavTrap::attack(target);
}

DiamondTrap&	DiamondTrap::operator=( DiamondTrap const& Diamond) {
	ClapTrap::operator=(Diamond);
	std::cout << "DiamondTrap " << this->Name << " operator= is called" << std::endl;
	return *this;
}

void	DiamondTrap::whoAmI() {
	std::cout << "DiamondTrap name is " << this->Name << " and ClapTrap name is " << ClapTrap::Name << std::endl;
}

-Wshadow, -Wno-shadlow

#include <iostream>

int main()
{
    int a;
    a = 3;
    {
        int a;
        a = 5;
        std::cout << a << std::endl;
    }
}

-Wshadow 옵션은 지역변수가 덮어씌워지거나 매개변수가 덮어씌워지면 경고를 해주는 옵션이다.
clang++ -Wshadow test.cpp 로 컴파일을 할 경우 경고를 해준다.
그리고 여기서 clang++ -Wshadow -Wno-shadow test.cpp 로 컴파일을 할 경우 두번째 사진처럼 경고가 없어진다.
-Wno-shadow는 -Wshadow의 경고가 안나오게 해주는 옵션이다.

0개의 댓글