어려움
//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;
}