카테고리 없음

03 - 30 C++ 보충 2-2챕터

pp4037 2026. 3. 31. 00:58

 

어려움

//Marine.h
#pragma once
#include <iostream>
#include <string>

class Marine
{
public: // 외부에서 접근해야하는 멤버 변수, 함수이므로 class의 기본 접근제어자인 private를 public으로 변경.
	int vitality; // 생명력
	float speed; // 이동 속도
	int attack; // 공격력
	int defense; // 방어력
	float attackSpeed; // 공격 속도
	int range; // 사거리
	std::string armorType; // 장갑 타입
	std::string Type; // 타입

	void Chat();
	void Move();
	void Attack();
	void UseStimpack(int invitality, float inspeed, float inattackSpeed);
	void CombatShield(int invitality);
};
// Marine.cpp
#include "Marine.h"
#include <iostream>
#include <string>

void Marine::Chat() // 이 함수는 일반 지역 함수인 void Chat이 아니라, Marine 이라는 클래스 내에 있는 멤버 함수다. 라는 걸 알려야함.
// 따라서 범위 지정 연산자인 ::을 사용해 자료형 클래스명::함수명(매개변수)를 통해 이 함수는 이 클래스에 있는 멤버 함수라는 걸 알림.
{
	std::cout << "출동 준비 완료!" << std::endl;
}

void Marine::Move()
{
	std::cout << "긴장 풀자구, 친구들." << std::endl;
}

void Marine::Attack()
{
	std::cout << "돌격 앞으로!" << std::endl;
}

void Marine::UseStimpack(int invitality, float inspeed, float inattackspeed)
{
	std::cout << "기분 좋은데?" << std::endl;

	invitality -= 10;
	inspeed *= 2;
	inattackspeed *= 5;

}

void Marine::CombatShield(int invitality)
{
	std::cout << "이 방패 정말 안전한 거 맞지?" << std::endl;

	invitality += 10;
}
// main.cpp
#include <iostream>
#include <string>
#include "Marine.h"



int main() 
{
	Marine Marine1; // 이 Marine1이라는 것은 Marine이라는 틀을 통해 찍어내는 물체 라는 걸 선언.
	// 이 시점에서 Marine1은 Marine의 안에 있는 모든 멤버 변수, 함수를 지니고 있음.
	Marine1.vitality = 45; // Marine1 이라는 구조체 변수에 있는 멤버 함수에 접근하기 위해 . 이라는 접근 연산자를 붙임.
    //그리고 어떤 멤버 변수에 접근할 건지 멤버 변수명을 통해 선언.
	Marine1.speed = 2.25;
	Marine1.attack = 6;
	Marine1.defense = 0;
	Marine1.attackSpeed = 0.8608;
	Marine1.range = 5;

	Marine1.Chat();
    // 이게 그냥 Chat이라는 함수인지, Marine1에 포함된 멤버 함수인지 알 수 없음.
    // 때문에 구조체 변수명을 먼저 알려서 이게 그 구조체 변수의 틀인 구조체에 있는 멤버 함수라는 걸 알림.
    // 그리고 .(접근 연산자) 를 통해 그 구조체 안에 있는 멤버 변수나 함수에 접근.
    // 무사히 구조체에 접근했다면 어떤 멤버 함수, 변수를 호출할 건지 명칭으로 정한다.
	Marine1.Move();
	Marine1.Attack();
	Marine1.UseStimpack(Marine1.vitality, Marine1.speed, Marine1.attackSpeed);
    // 그냥 speed 라고 적으면 Marine1의 speed인지 아니면 Marine2의 speed인지 알 수 없음.
    // 따라서 Marine1 이라는 구조체 변수라는 걸 먼저 선언
    // 구조체 변수 내에 있는 멤버 변수에 접근하기 위해 . 를 붙이고 멤버 변수명 선언.
	Marine1.CombatShield(Marine1.vitality);

	return 0;
}
// Main.cpp

class Human // class 클래스명으로 클래스 생성
{
public: // class의 접근제어자 기본값은 private이기 때문에 외부에서 이 멤버변수에 접근할 수 있게끔 public으로 변경한다.
	float Height;

	float Weight;

};

int main(void)
{
	// 아래 코드는 한 세트.
	Human* Park = new Human(); // 힙 메모리를 기반으로 공간이 할당되어 있는 클래스 Human에 접근하기 위해 Human의 메모리주소에 접근할 수 있는 포인터(Human*)를 먼저 클래스명과 함께 붙인다.
	// Park == 해당하는 클래스(Human)의 객체 이름으로 클래스에 존재하는 모든 멤버변수를 기본으로 지니고 있다. 
	// new Human : new == 단어 그대로 '새로운' Human(클래스명) 클래스 객체 라는 것.
	// 요약하자면 Park은 Human 클래스의 메모리공간에 새롭게 만들어진 객체.
	/* ... Do something ... */
	// 해당하는 방식은 일반적인 객체 생성과는 다르다.
	// 일반적인 객체 생성은 스택 메모리 기반의 지역변수이기에 함수가 끝나면 사라진다.
	// new 키워드로 생성된 객체는 const 키워드와 같이 별도의 메모리 공간에 값이 할당된다.
	// 따라서 new 키워드로 생성된 객체는 지우지 않을 시 메무리 누수가 발생한다.
	delete Park; // 먼저 Park 이라는 객체를 지운다. 하지만 지워도 Park이 차지했던 메모리 공간의 값은 지워지지 않는다.
	Park = nullptr; // Park이 차지했던 메모리 공간의 값을 null(아무것도 없음) + ptr(포인터) 키워드로 지운다.

	// 아래 코드는 한 세트.
	Human* ClassMates = new Human[30];
	/* ... Do something ... */
	delete[] ClassMates; // 배열의 경우에도 똑같다.
	ClassMates = nullptr;

	/*
		nullptr 대입이 필수는 아닙니다.
		다만, delete 후에 nullptr 대입하지 않으면 메모리 해제된 주소를 그대로 갖고 있게 됩니다.
		이는 댕글링 포인터이고, 사용하게 되면 문제를 일으키게 됩니다.
		따라서 nullptr을 대입해주는 게 좋습니다.
	*/

	return 0;
}

 

 

어려움

// Main.cpp

#include <crtdbg.h> // _CrtSetDbgFlag(), _CrtSetBreakAlloc() 을 사용하기 위한 공구통

class Human
{
public:
	float Height;

	float Weight;

};

int main(void)
{
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
	// 메모리 릭 추적.
// _CrtSetBreakAlloc(161);
	// 메모리 릭 지점에 자동으로 중단점을 걸어주는 함수.
	// _CrtSetDbgFlag == 안에 들어있는 변수들의 플래그를 설정하는 함수
	// Output 레이아웃에 있는 Show output from 드롭다운을 Debug로 변경.
	// Output 로그에서 메모리릭이 탐지되면 그곳을 메모리 블록으로 알려줌.
	// _CrtSetBreakAlloc(); 함수에 () 안에 해당 숫자를 기입.
	// 이후 빌드 실행 시 오류가 뜨면서 Call Stack에서 어느 파일에서 new 이후 delete를 안 했는지 알려줌.
	Human* Park = new Human();

	//delete Park;
	//Park = nullptr;

	

	return 0; // 함수가 끝났을 때 메모리 릭을 더는 추적할 수 없게 된다.
	// 동적할당 항목에서 malloc() 함수가 해당 함수 내에서만 free() 함수로 해제되어야만 하는 것과 같은 원리
}
// Main.cpp

struct SMyVector // struct == 구조체, 기본 접근 제어자는 public으로 외부에서 멤버 변수, 함수를 호출할 수 있음.
{
	float X;

	float Y;

};

class CMyVector // class == 클래스, 기본 접근 제어자는 private로 외부에서 멤버 변수, 함수를 호출할 수 없다.
{
// 오류를 없애고 싶다면 해당 줄에 public: 으로 접근 제어자를 변경해야한다.
	float X;

	float Y;

};

int main(void)
{
	SMyVector V01; 
	V01.X;
	V01.Y;

	CMyVector V02;
	V02.X; // 접근할 수 없는 멤버 변수에 접근했기에 오류가 나온다. 
	V02.Y;

	return 0;
}

 

 

어려움

// Main.cpp
// 1:29:00

#include <iostream>

class ParentClass
{
public:
	void PrintOtherObjectPrivateValue(const ParentClass& InOtherObject) // 본인
	{
		std::cout << "PrivateValue: " << PrivateValue << std::endl;
		// private은 자기 자신 클래스의 멤버 함수 내에서 접근 가능.

		std::cout << "OtherObject->PrivateValue: " << InOtherObject.PrivateValue << std::endl;
		// 다른 객체의 private 멤버 변수더라도, 클래스의 멤버 함수 내이므로 접근 가능.
	}

public:
	int PublicValue;

protected:
	int ProtectedValue;

private:
	int PrivateValue;

};

class ChildClass : public ParentClass
{
public:
	void PrintValues() // 자식
	{
		std::cout << "PublicValue: " << PublicValue << std::endl;
		// public은 자식 클래스의 멤버 함수에서 접근 가능
		std::cout << "ProtectedValue: " << ProtectedValue << std::endl;
		// protected는 자식 클래스의 멤버 함수에서 접근 가능
	// std::cout << "PrivateValue: " << PrivateValue << std::endl;  
		// private은 자식 클래스의 멤버 함수에서 접근 불가
	}

};

int main(void) // 외부 
{
	ParentClass ParentObject;
	ChildClass ChildObject;

	ParentObject.PrintOtherObjectPrivateValue(ChildObject);

	ChildObject.PrintValues();

	std::cout << ParentObject.PublicValue << std::endl;			// public은 클래스 외부에서 접근 가능
	// std::cout << ParentObject.ProtectedValue << std::endl;	// protected는 클래스 외부에서 접근 불가
	// std::cout << ParentObject.PrivateValue << std::endl;		// private은 클래스 외부에서 접근 불가

	return 0;
}

 

 

 

 

// Human.h

#pragma once

class Human
{
public:
	Human(); // 생성자를 선언하는 방법.
	// int Human; == 멤버 변수를 선언하는 방법.
	// void Human(); == 멤버 함수를 선언하는 방법.

private:
	float Height;

	float Weight;

};
// Human.cpp

#include "Human.h"

#include <iostream>

using namespace std;

Human::Human() // 일반 멤버 함수와는 다르다. 차이점 : 반환자료형 유무
// 구조체명::(범위 지정자)생성자명()
// 일반 멤버 함수의 경우 클래스명::(범위 지정자)함수명 -> 지역 함수인지 멤버 함수인지 구분하기 위해 클래스명:: 을 꼭 붙여야함.
{
	cout << "Human() constructor has been called." << endl;
}
// Main.cpp

#include <iostream>

#include "Human.h"

int main(void)
{
	Human Human01 = Human(); // 구조체명 구조체변수명 = 생성자명();
	// 생성자를 명시적으로 호출해서 객체를 만들고, 그걸 다시 Human01에 대입.
	// Human Human01; != Human Human01 = Human();
	// 이미 Human() 단계에서 객체가 만들어졌다. 그 만들어진 객체를 Human 이라는 구조체라는 틀을 가진 구조체 변수(객체)에 대입시킨 것.
	// 대입되었기 때문에 Human.cpp 파일에서 생성자 Human()의 함수로 지정된 것이 자동으로 들어감.
	Human* Human02 = new Human();
	// 생성자의 명시적 호출.

	Human Human03;
	// 생성자의 암시적 호출.
	Human* Human04;
	// Q. 이건 무슨 일이 벌어질까요?

	delete Human02;
	Human02 = nullptr;

	return 0;
}

 

 

어려움

// Main.cpp

#include <iostream>

class Class01
{
public:
	Class01() // Class01() 생성자를 선언...? ; 이 없음.
	{
		std::cout << "Class01's Constructor" << std::endl;
	}

};

class Class02
{
public:
	Class02()
	{
		std::cout << "Class02's Constructor" << std::endl;
	}

};

class Class03
{
public:
	Class03()
	{
		std::cout << "Class03's Constructor" << std::endl;
	}

public:
	Class01 Member01; // 값자료...?

	Class02 Member02; // 클래스명 변수명; == 클래스명이 가리키는 클래스에 속하는 멤버 변수.
	// 메모리 주소만 저장할 수 있다고 하며 메모리 주소를 넣어준다고는 안함...?
	// 메모리 주소값을 넣을 수 있는 변수만 선언하고 메모리 주소값을 넣어준다고는 안함...?
};

int main(void)
{
	Class03 Object = Class03();

	return 0;
}

 

 

 

// Human.h

#pragma once

class Human
{
public:
	Human(); // Human이라는 클래스에 있고 외부에서 접근할 수 있는 생성자 선언.

private:
	float Height; // 외부에서 접근할 수 없는 멤버 변수

	float Weight;

};
// Human.cpp

#include "Human.h"

#include <iostream>

using namespace std;

Human::Human() // Human이라는 구조체의 ::(영역 지정자) 영역에 있는 Human(생성자)
	: Height(0.0f)
	, Weight(0.0f) // 이것들은 객체가 만들어짐과 동시에 초기화됨.
    // 사용할 때 : 참조자를 생성할 때.
    // 참조자는 생성 후 초기화가 안됨.

	// : A;
	// , B;
	// , C;
	// 이런 식...?
{
	cout << "Human() constructor has been called." << endl;

	// 아래와 같이 작성하는 것과 Initializer List를 활용하는 것은 다름.
	// Height = 0.0f;
	// Weight = 0.0f;
}	// 객체가 만들어진 후에 초기화.

 

// Main.cpp

#include <iostream>

class MyClass
{
public:
	// 생성자를 정의하지 않았습니다.

};

int main(void)
{
	MyClass Object = MyClass(); // Q. 무슨 일이 왜 벌어질까요?
	// 생성자가 정의되지 않을 시 기본 생성자가 자동으로 정의된다.
	// 만들어지는 이유는 '기본' 이기에 C++ 프로그램 내에서 자동으로 정의시킴.

	return 0;
}
// Main.cpp

#include <iostream>

class MyClass
{
public:
	MyClass(int InA)
	{
		std::cout << "MyClass's Constructor" << std::endl;
	}

};

int main(void)
{
	MyClass Object01;	// Q. 무슨 일이 왜 벌어질까요?
	// 이 경우에는 이미 생성자가 존재하기 때문에 기본 생성자가 만들어지지 않는다.
	// 생성자가 있기에 '기본' 생성자는 비활성화됨.
	MyClass Object02 = MyClass();

	return 0;
}

 

 

// Human.h
// 오버로딩 : 같은 함수명이지만 매개변수 목록을 다르게 함수를 재정의하는 것.
#pragma once

class Human
{
public:
	Human();

	Human(float InHeight, float InWeight, int InBirthDay);
	// 위의 두 생성자가 오버로딩 예시.
private:
	float Height;

	float Weight;

	const int BirthDay;

};

// 오버로딩이라는 개념이 없는 세계선...

int Add(int, int);
// 팀원들에게 "덧셈 할려면 Add() 함수 쓰세요~!"

// 어? float 덧셈하려는데 Add() 함수 쓰니까 이상한거 나오는데요?

float Accumulate(float, float);
// 아! float 덧셈은 Accumulate() 함수 쓰셔야 합니다.
// 아니;;; 아까는 덧셈할때 Add() 함수 쓰라면서요;;;

// 오버로딩이라는 개념이 생긴 세계선.
int Add(int, int);
float Add(float, float);
// Human.cpp

#include "Human.h"

#include <iostream>

using namespace std;

Human::Human()
	: Height(0.0f)
	, Weight(0.0f)
	, BirthDay(20260101)
{
	cout << "Human() constructor has been called." << endl;
}

Human::Human(float InHeight, float InWeight, int InBirthDay)
	: Height(InHeight)
	, Weight(InWeight)
	, BirthDay(InBirthDay)
{
	cout << "Human(float InHeight, float InWeight, int InBirthDay) constructor has been called." << endl;
}
// 이렇게 오버로딩을 하면 각각 다른 함수로 정의되기에 별도로 함수 안을 채워줘야한다.
// Main.cpp

#include <iostream>

#include "Human.h"

int main(void)
{	// 구조체 변수 선언을 하는 네 가지 방법
	Human Human1;
	Human Human2 = Human(175.4f, 72.2f, 18900304);
	Human* Human3 = new Human();
	Human* Human4 = new Human(161.5f, 48.0f, 19900202);

	delete Human3;
	Human3 = nullptr;
	delete Human4;
	Human4 = nullptr;

	return 0;
}

 

 

 

 

// Human.h

#pragma once

class Human
{
public:
	Human();

	Human(float InHeight, float InWeight, int InBirthDay);

	~Human(); // 소멸자?

private:
	float Height;

	float Weight;

	const int BirthDay;

};
// Human.cpp

#include "Human.h"

#include <iostream>

using namespace std;

Human::Human()
	: Height(0.0f)
	, Weight(0.0f)
	, BirthDay(20260101)
{
	cout << "Human() constructor has been called." << endl;
}

Human::Human(float InHeight, float InWeight, int InBirthDay)
	: Height(InHeight)
	, Weight(InWeight)
	, BirthDay(InBirthDay)
{
	cout << "Human(float InHeight, float InWeight, int InBirthDay) constructor has been called." << endl;
}

Human::~Human() // 이게 소멸자
{
	cout << "~Human() destructor has been called." << endl;
}
// 구조체명 ::(범위 지정자) 소멸자 키워드 생성자() 구조...?
// 소멸자는 오버로딩이 안된다.
// Main.cpp

#include <iostream>

#include "Human.h"

int main(void)
{
	Human Human1; // 이 구조체 변수는 지역 변수이기 때문에 함수 종료 시 자동으로 소멸자가 호출된다.
	Human Human2(175.4f, 72.2f, 18900304); // 이 구조체 변수는 스택 메모리에 있기에 자동으로 소멸되지 않는다.
	// 따라서 소멸자가 호출되지 않는다.
	Human* Human3 = new Human(); // 구조체 변수 == 지역 변수
	Human* Human4 = new Human(161.5f, 48.0f, 19900202); // 구조체 변수  != 지역 변수

	delete Human3; // 이 시점에서 소멸자가 호출된다.
	Human3 = nullptr;
	delete Human4;
	Human4 = nullptr;

	return 0;
}

 

 

 

 

// Human.h

#pragma once

class Human
{
public:
	Human();

	Human(float InHeight, float InWeight, int InBirthDay);

	Human(float InHeight, float InWeight, int InBirthDay, const char* InName);

	~Human();

	void PrintInfo();

private:
	float Height;

	float Weight;

	const int BirthDay;

	char* Name;

};
// Human.cpp

#define _CRT_SECURE_NO_WARNINGS

#include "Human.h"

#include <iostream>
#include <cstring>

using namespace std;

Human::Human()
	: Height(0.0f)
	, Weight(0.0f)
	, BirthDay(20260101)
	, Name(nullptr)
{
	cout << "Human() constructor has been called." << endl;

	Name = new char[8];
	strcpy(Name, "None");
}

Human::Human(float InHeight, float InWeight, int InBirthDay)
	: Height(InHeight)
	, Weight(InWeight)
	, BirthDay(InBirthDay)
	, Name(nullptr)
{
	cout << "Human(float InHeight, float InWeight, int InBirthDay) constructor has been called." << endl;

	Name = new char[8];
	strcpy(Name, "None");
}

Human::Human(float InHeight, float InWeight, int InBirthDay, const char* InName)
	: BirthDay(InBirthDay)
{
	cout << "Human(float InHeight, float InWeight, int InBirthDay, const char* InName) constructor has been called." << endl;

	Height = InHeight;
	Weight = InWeight;

	Name = new char[strlen(InName) + 1];
	strcpy(Name, InName);
}

Human::~Human()
{
	cout << "~Human() destructor has been called." << endl;

	if (Name != nullptr) // 만약 Name 멤버 변수가 nullptr이 아니라면. Name은 헤더파일에서 포인터로 정의되었기에 메모리주소값에 접근 가능.
	{
		delete[] Name; // Name 멤버 변수가 있는 메모리 주소를 삭제해라.
		Name = nullptr; // 삭제한 메모리 주소를 비워라.
	}
}

void Human::PrintInfo()
{
	cout << "Height: " << Height << " cm" << endl;
	cout << "Weight: " << Weight << " kg" << endl;
	cout << "BirthDay: " << BirthDay << endl;
	cout << "Name: " << Name << endl;
}
// Main.cpp

#include <crtdbg.h> // _CrtSetDbgFlag(), _CrtSetBreakAlloc()

#include "Human.h"

int main(void)
{
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
	// 메모리 릭 추적.

	Human Kim = Human(182.0f, 75.0f, 19990101, "Kim");
	Human Lee(182.0f, 75.0f, 19990101);
	Human Park;
	// 세 구조체 변수 모두 힙 메모리에 속해있는 지역 변수...?

	Kim.PrintInfo();
	Lee.PrintInfo();
	Park.PrintInfo();

	// Q. 메모리 릭이 날까요? 안난다면 왜 안날까요?
	// 소멸자의 함수 코드에 delete 함수를 넣었기에 나지 않을거 같습니다.
    
	return 0;
}

 

 

 

// Human.cpp

#define _CRT_SECURE_NO_WARNINGS

#include "Human.h" // Human.h의 코드를 불러옴

#include <iostream>
#include <cstring>

using namespace std;

Human::Human() // Human 클래스 범위 안에 있는 Human 생성자
	: Height(0.0f) // Initializer List : 사용하는 이유 == 초기화되기 전 값을 먼저 대입시켜서 참조자와 같은 것에 사용하기 위함
	, Weight(0.0f) // Weight 멤버변수에 (0.0f) 값을 대입시킨다.
	, BirthDay(20260101) // BirthDay 멤버변수에 (20260101) 값을 대입시킨다.
	, Name(nullptr) // Name 멤버변수를 (nullptr)로 초기화시킨다.
	// nullptr == 어떤 메모리주소도 없는 것
{
	cout << "Human() constructor has been called." << endl;

	Name = new char[8]; // 힙메모리에 저장되어있는 char 자료형 배열(8 공간이 있는)을 
	// 헤더 파일에 있는 char* Name; 라는 char 자료형의 포인터 Name에 대입시킨다.
	strcpy(Name, "None"); //strcpy 이라는 함수를 호출하며, (매개변수로 Name, "None")을 인자값으로 제공한다.
}

Human::Human(float InHeight, float InWeight, int InBirthDay)
// Human 클래스 범위지정자 Human이라는 생성자(자료형 매개변수명)
	: Height(InHeight) // Initializer List를 사용해서 멤버변수에 값을 대입시킨다.
	, Weight(InWeight) // Weight라는 멤버변수에 InWeight라는 매개변수의 값을 대입시킨다.
	, BirthDay(InBirthDay)
	, Name(nullptr) 
{
	cout << "Human(float InHeight, float InWeight, int InBirthDay) constructor has been called." << endl;

	Name = new char[8];
	strcpy(Name, "None");
}

Human::Human(float InHeight, float InWeight, int InBirthDay, const char* InName)
	: BirthDay(InBirthDay) // Initializer List를 사용해서 BirthDay 멤버변수에 InBirtDay값을 대입시킨 뒤 초기화한다.
{
	cout << "Human(float InHeight, float InWeight, int InBirthDay, const char* InName) constructor has been called." << endl;

	Height = InHeight;
	Weight = InWeight;

	Name = new char[strlen(InName) + 1]; // new(새로운 구조체 변수) char(자료타입) 배열[] strlen...? (Inname이라는 매개변수의 값에) +1을 더한 만큼 배열의 메모리 크기로 잡는다...?
	strcpy(Name, InName);
}

Human::~Human()
{
	cout << "~Human() destructor has been called." << endl;

	if (Name != nullptr) // Name의 메모리값이 nullptr(메모리주소값이 비어있음) 과 같지 않다면
	{
		delete[] Name; // Name이라는 객체를 지운다.
		Name = nullptr; // Name의 메모리주소 공간을 nullptr로 대입시킨다.
	}
}

//void Human::PrintInfo()
void Human::PrintInfo() const
// const == 이 함수를 호출한 객체 내부에 있는 멤버값을 바꾸지 않겠다. (읽기 전용으로 만들겠다.)
// 객체 == 구조체 변수. Human h; h.PrintInfo() 에서 h가 객체.
{
	cout << "Height: " << Height << " cm" << endl;
	cout << "Weight: " << Weight << " kg" << endl;
	cout << "BirthDay: " << BirthDay << endl;
	cout << "Name: " << Name << endl;

	//Height = 185.0f; // 이 코드는 어떻게 될까요? 
	// 컴파일 오류가 나온다. 읽기 전용 함수에 값을 대입시키는 코드는 사용할 수 없다.
}
// Human.h
// const 멤버 함수
// 함수 내부에서 클래스의 멤버 변수를 수정하지 못하는 함수
// 주로 출력만 하는 함수나 getter 함수에 쓰임
// 40 : 10
#pragma once

class Human // Human 클래스
{
public: // 기본 접근제어자가 private이기 때문에 public으로 변경
	Human(); // 생성자

	Human(float InHeight, float InWeight, int InBirthDay); // 생성자 오버로딩

	Human(float InHeight, float InWeight, int InBirthDay, const char* InName); // 생성자 오버로딩

	~Human(); // 소멸자

	//void PrintInfo();
	void PrintInfo() const; // 멤버 함수 + 함수 내부에서 클래스의 멤버 변수를 수정하지 못함. 
	// 반환자료명 멤버함수명(자료형 매개변수명) const 키워드
private:
	float Height;

	float Weight;

	const int BirthDay;

	char* Name;

};
// Human.h
// // 50 : 00
// Getter Setter
// 객체의 멤버 변수를 외부에서 직접 접근 할 수 없게 만들어서 보호하는 함수
// 멤버 변수 중 private 접근 지정자로 정해져있는 변수는 클래스 외부에서 접근이 불가능하다.
// 이런 변수에 접근해서 값을 반환하는 것이 getter 함수 // 반환자료형 get멤버변수명(매개변수명) const;
// 이런 변수에 접근해서 값을 수정하는 것이 setter 함수 // 반환자료형 get멤버변수명(매개변수명);
#pragma once

class Human
{
public:
	Human();

	Human(float InHeight, float InWeight, int InBirthDay);

	Human(float InHeight, float InWeight, int InBirthDay, const char* InName);

	~Human();

	void PrintInfo() const;

	float GetHeight() const; // Getter 함수. 멤버 변수의 값을 반환하기만 할거라 멤버 변수 수정은 제한함.
	// 반환자료형 Get멤버변수명(매개변수자료형 매개변수명) const;
	// const를 붙이는 이유는 멤버변수의 값만 반환하고 별도의 수정을 하지 않기에 읽기 전용으로 만들기 위해서.

	void SetHeight(float InHeight); // Setter 함수. 멤버 변수를 수정하기 때문에 const 멤버 함수가 아님.
	// 반환자료형 set멤버변수명(매개변수자료형 매개변수명);
	// const를 붙이지 않는 이유는 멤버변수의 값을 호출할 뿐만 아니라 멤버 변수의 값을 수정하기 때문.
	// setter 함수를 사용하는 이유는 함수의 예외처리 부분을 맡기 위해서.
	float GetWeight() const;

	void SetWeight(float InWeight);

private:
	float Height; // 현재 getter 함수와 setter 함수는 이 멤버변수를 가져오려고 하고 있다.

	float Weight;

	const int BirthDay;

	char* Name;

};
// Main.cpp
// 챕터 2-7 : 클래스 전방 선언과 friend 키워드 
// 59 : 00
class PlayerCharacter
{
public:
	Inventory* MyInventory; // Inventory라는 클래스가 앞에 없기에 Inventory라는 클래스를 인식 못함

};

class Inventory
{
};

int main(void)
{

	return 0;
}
// Main.cpp

class Inventory;
// 클래스 전방 선언

class PlayerCharacter
{
public:
	Inventory* MyInventory;
};

class Inventory
{
};

int main(void)
{

	return 0;
}
// Main.cpp

class Inventory;

class PlayerCharacter
{
public:
	Inventory MyInventory; 
	// Inventory 라는 클래스의 멤버변수, 함수를 품고 있는 객체(구조체 변수)를 만드는 거기에 오류가 일어난다.
	// 포인터가 아닐 경우 이 클래스는 전방선언으로는 부족하고 앞에 모두 정의되어있어야 한다.
	// 전방선언으로는 불가능하다.
	// 포인터는 메모리주소값을 지니고 있기에 주소 위치만 알고 있어서 전방선언으로 충분하다.
	// 객체의 경우 그 클래스가 담고 있는 멤버변수, 함수가 뭐가 있는지 전부 알아야하기에 전방선언은 불가능하다.
};

class Inventory
{
};

int main(void)
{
	// PlayerCharacter* Me; == Me라는 이름을 가진, PlayerCharacter의 메모리 주소값을 지닌 포인터
	// 메모리 주소값을 저장하는 변수.
	// 메모리 주소는 채워지지 않았다. 집주소만 있고 집터는 아무것도 없는 상황.
	// 만들려면 PlayerCharacter* Me = new PlayerCharacter(); 을 써야한다.
	// 이 경우 함수가 끝나기 전에 Me delete; Me = nullptr; 을 해서 힙 메모리에 빌려온 메모리공간을 비우고 반납해야 메모리 누수가 일어나지 않는다.
	// 혹은 PlayerCharacter Me;를 쓰면되고 이 경우 윗줄의 뒷처리를 거칠 필요 없다.

	return 0;
}
// Main.cpp

class Inventory;

class PlayerCharacter
{
public:
	Inventory MyInventory; 
	// Inventory 라는 클래스의 멤버변수, 함수를 품고 있는 객체(구조체 변수)를 만드는 거기에 오류가 일어난다.
	// 포인터가 아닐 경우 이 클래스는 전방선언으로는 부족하고 앞에 모두 정의되어있어야 한다.
	// 전방선언으로는 불가능하다.
	// 포인터는 메모리주소값을 지니고 있기에 주소 위치만 알고 있어서 전방선언으로 충분하다.
	// 객체의 경우 그 클래스가 담고 있는 멤버변수, 함수가 뭐가 있는지 전부 알아야하기에 전방선언은 불가능하다.
	// 때문에 클래스를 위쪽에 작성하거나, 다른 헤더파일에 작성해 그것을 #include "if.h" 등으로 불러온다.
};

class Inventory
{
};

int main(void)
{
	// PlayerCharacter* Me; == Me라는 이름을 가진, PlayerCharacter의 메모리 주소값을 지닌 포인터
	// 메모리 주소값을 저장하는 변수.
	// 메모리 주소는 채워지지 않았다. 집주소만 있고 집터는 아무것도 없는 상황.
	// 만들려면 PlayerCharacter* Me = new PlayerCharacter(); 을 써야한다.
	// 이 경우 함수가 끝나기 전에 Me delete; Me = nullptr; 을 해서 힙 메모리에 빌려온 메모리공간을 비우고 반납해야 메모리 누수가 일어나지 않는다.
	// 혹은 PlayerCharacter Me;를 쓰면되고 이 경우 윗줄의 뒷처리를 거칠 필요 없다.

	return 0;
}