[C++] 구조체/생성자와 소멸자/동적할당/동적배열/상속/가상함수
2022. 6. 13. 19:48ㆍ돌다리도 두드려보고 건너라 <복만살>
728x90
/* 학습목차
1. 구조체
2. 생성자와 소멸자
3. 동적할당
4. 동적배열
5. 상속
6. 가상함수
*/
#include <iostream>
#include <string>
using namespace std;
// 구조체
// 직접 만드는 쓰는 서로다른 데이터타입의 집합체
// 기능(멤버함수)과 속성(멤버변수)을 지닌 사용자 정의의 데이터타입
struct Monster
{
string name;
int hp;
int atk;
void SetInfo(string _name, int _hp, int _atk)
{
name = _name;
hp = _hp;
atk = _atk;
}
void ShowInfo()
{
cout << name << endl;
cout << hp << endl;
cout << atk << endl;
}
void Attack()
{
}
void Hit()
{
}
void Die()
{
}
};
void main()
{
Monster monsterA;
Monster* monsterAPtr;
monsterA.SetInfo("몬스터A", 100, 10);
monsterAPtr = &monsterA;
monsterAPtr->name = "템프";
monsterA.ShowInfo();
}
// 생성자와 소멸자
// 생성자 : 메모리에 할당이 될때 호출된다, 초기화의 기능이 있다
// 생성자는 기본생성자와 복사생성자가 있다
// 소멸자 : 메모리에서 해제될때 호출된다
struct Monster
{
string name;
int hp;
int atk;
// 생성자 문법 : 구조체이름()
Monster()
{
cout << "생성자 호출" << endl;
}
// 생성자 오버로딩
Monster(string _name, int _hp, int _atk)
{
SetInfo(_name, _hp, _atk);
cout << name << "생성자 호출" << endl;
}
// 소멸자 문법 : ~구조체이름()
~Monster()
{
cout << name << "소멸자 호출" << endl;
}
void SetInfo(string _name, int _hp, int _atk)
{
name = _name;
hp = _hp;
atk = _atk;
}
void ShowInfo()
{
cout << name << endl;
cout << hp << endl;
cout << atk << endl;
}
};
Monster monsterC("C", 100, 10); // 전역변수 - 데이터영역
void main()
{
Monster monsterA("A", 100, 10); // 매개변수, 지역변수 - 스택영역
Monster monsterB("B", 100, 10);
// 포인터변수는 주소를 담는 변수일뿐, Monster가 아니다
// 아래 포인터변수는 주소를 Monster의 형태로 해석할 뿐
Monster* monsterAPtr;
}
// 동적할당
// new 데이터타입 동적할당을 하면 데이터타입의 크기만큼 Heap 메모리 영역에 할당하고
// 그 시작주소를 반환한다 (메모리에 할당되니까 생성자 호출됨)
// 동적할당을 했으면 다시 해제를 해줘야 한다(delete) 하지않으면 메모리누수 발생
// 컴파일시점과 런타임시점 중 동적할당은 런타임(실행되고 난 이후)에 해당함
struct Monster
{
string name;
int hp;
int atk;
Monster()
{
cout << "생성자 호출" << endl;
}
Monster(string _name, int _hp, int _atk)
{
SetInfo(_name, _hp, _atk);
cout << name << "생성자 호출" << endl;
}
~Monster()
{
cout << name << "소멸자 호출" << endl;
}
void SetInfo(string _name, int _hp, int _atk)
{
name = _name;
hp = _hp;
atk = _atk;
}
void ShowInfo()
{
cout << name << endl;
cout << hp << endl;
cout << atk << endl;
}
};
Monster monsterC("C", 100, 10);
void main()
{
int num = 10;
int* numPtr = new int;
*numPtr = 30;
cout << *numPtr << endl;
delete numPtr;
Monster monsterA("A", 100, 10);
Monster monsterB("B", 100, 10);
Monster* monsterAPtr = new Monster("D", 100, 10);
// 메모리 누수 발생 - 동적할당은 delete를 해야한다
delete monsterAPtr;
}
// 동적배열
struct Monster
{
string name;
int hp;
int atk;
Monster()
{
cout << "생성자 호출" << endl;
}
Monster(string _name, int _hp, int _atk)
{
SetInfo(_name, _hp, _atk);
cout << name << "생성자 호출" << endl;
}
~Monster()
{
cout << name << "소멸자 호출" << endl;
}
void SetInfo(string _name, int _hp, int _atk)
{
name = _name;
hp = _hp;
atk = _atk;
}
void ShowInfo()
{
cout << name << endl;
cout << hp << endl;
cout << atk << endl;
}
};
// 동적할당을 통해 주소를 넘겨주어야 한다. textrpg만들때 자주 쓰임(예를 들면 캐릭터생성시)
// 따로 해제를 해주지 않은 이상 주소가 남기때문이다.
// 지역변수를 통해 넘기려고 하면, 지역변수는 괄호가 끝나면서 할당이 해제되기때문
// 후에 사용할 때 문제가 생길 수 있다
// Monster temp;
// temp.SenInfo(name,hp,atk);
// return &temp;
// 따라서 함수 내에서 생성한 객체를 넘기고 싶다면 동적할당을 통해 넘겨준다.
Monster* CreateMonster()
{
string name;
cout << "생성할 몬스터의 이름을 입력하시오 : ";
cin >> name;
int hp;
cout << "생성할 몬스터의 체력을 입력하시오 : ";
cin >> hp;
int atk;
cout << "생성할 몬스터의 공격력을 입력하시오 : ";
cin >> atk;
return new Monster(name, hp, atk);
}
void main()
{
Monster* monsters[3];
monsters[0] = new Monster("A", 100, 10);
monsters[1] = new Monster("B", 150, 10);
monsters[2] = new Monster("C", 200, 10);
Monster* createMonster;
createMonster = CreateMonster();
createMonster->ShowInfo();
delete createMonster;
for (int i = 0; i < 3; i++)
{
monsters[i]->ShowInfo();
delete[] monsters[i];
}
}
// 상속
// 상속을 하는 2가지 경우는
// ①중복이 되서 합치는 경우 ②같은 곳에서 관리하기 위해서 하는 경우가 있다.
// 공통분모를 하나로 추상화(통합)하는 과정
// 부모 구조체
struct SchoolMember
{
string name;
int id;
void SetInfo(string _name, int _id)
{
name = _name;
id = _id;
}
void ShowInfo()
{
cout << "교내 멤버정보" << endl;
cout << name << id << endl;
}
};
// 상속 : 부모가 자식에게 속성과 기능, 그리고 정체성을 물려주는 것
// [문법]상속받을 구조체명 : 상속할 구조체명
// is a 관계 = 선생은 학교멤버이다
struct Teacher : SchoolMember
{
string subject;
// 함수의 오버라이딩 : 재정의
// 부모의 함수를 자식에서 재정의하는 것
void SetInfo(string _name, int _id, string _subject)
{
SchoolMember::SetInfo(_name, _id);
subject = _subject;
}
void ShowInfo()
{
cout << "선생정보" << endl;
cout << name << id << subject << endl;
}
void Teach()
{
}
};
// is a 관계 = 학생은 학교멤버이다
struct Student : SchoolMember
{
int grade;
// 함수의 오버라이딩 : 재정의
void SetInfo(string _name, int _id, int _grade)
{
name = _name;
id = _id;
grade = _grade;
}
void ShowInfo()
{
cout << "학생정보" << endl;
cout << name << id << grade << endl;
}
void Study()
{
}
};
void main()
{
Student studentA;
studentA.SetInfo("학생A", 1, 4);
Teacher teacherA;
teacherA.SetInfo("선생A", 1, "과학");
studentA.ShowInfo();
teacherA.ShowInfo();
SchoolMember tempMember;
// 선생과 학생이 학교의 멤버이기때문에 들어갈 수 있다
// 복사되어 들어갈때, SchoolMember의 형태에 맞도록 짤려서 복사되기 때문에 Student의 기능들 또한 짤리게 된다
tempMember = studentA; // 된다
cout << "현재 임시 멤버는 : ";
tempMember.ShowInfo();
tempMember = teacherA; // 된다
cout << "현재 임시 멤버는 : ";
tempMember.ShowInfo();
}
// 가상함수
// 부모의 함수에 virtual를 붙인것
// 함수가 호출 될 때, 자식에서 재정의가 되었는지 확인하고 재정의가 되었다면 자식의 함수를 호출함
struct SchoolMember
{
string name;
int id;
SchoolMember()
{
}
SchoolMember(string _name, int _id)
{
name = _name;
id = _id;
}
void SetInfo(string _name, int _id)
{
name = _name;
id = _id;
}
void virtual ShowInfo()
{
cout << "교내 멤버정보" << endl;
cout << name << id << endl;
}
// 가상소멸자
virtual ~SchoolMember()
{
cout << name << "교내멤버소멸자" << endl;
}
};
struct Teacher : SchoolMember
{
string subject;
Teacher()
{
}
Teacher(string _name, int _id, string _subject) : SchoolMember(_name, _id)
{
subject = _subject;
}
~Teacher()
{
cout << name << "선생소멸자" << endl;
}
void SetInfo(string _name, int _id, string _subject)
{
SchoolMember::SetInfo(_name, _id);
subject = _subject;
}
void ShowInfo()
{
cout << "선생정보" << endl;
cout << name << id << subject << endl;
}
void Teach()
{
}
};
struct Student : SchoolMember
{
int grade;
Student()
{
}
Student(string _name, int _id, int _grade) : SchoolMember(_name, _id)
{
grade = _grade;
}
~Student()
{
cout << name << "학생소멸자" << endl;
}
void SetInfo(string _name, int _id, int _grade)
{
name = _name;
id = _id;
grade = _grade;
}
void ShowInfo()
{
cout << "학생정보" << endl;
cout << name << id << grade << endl;
}
void Study()
{
}
};
void main()
{
SchoolMember* schoolMembers[4];
schoolMembers[0] = new Student("학생A", 0, 4); // 업케스팅
schoolMembers[1] = new Student("학생B", 0, 3);
schoolMembers[2] = new Student("학생C", 0, 2);
schoolMembers[3] = new Teacher("선생A", 0, "물리");
for (int i = 0; i < 4; i++)
{
schoolMembers[i]->ShowInfo();
}
// 가상 소멸자 생성
for (int i = 0; i < 4; i++)
{
delete schoolMembers[i];
}
/*
Teacher teacherA;
teacherA.SetInfo("선생", 1, "과학");
// 같은 주소를 가르키더라도 포인터변수 데이터타입의 형태에 따라 해석의 범위가 달라진다
Teacher* teacherPtr;
teacherPtr = &teacherA;
teacherPtr->ShowInfo();
SchoolMember* schoolMemberPtr;
schoolMemberPtr = &teacherA; // 업케스팅 : 자식에서 부모로 올라가는 것
// 부모의 형태->ShowInfo()를 호출할때 ShowInfo가 virtual함수이므로 자식에서 재정의가 되었는지 확인
// 자식 Teacher에는 재정의가 되어있기 때문에 재정의 되어있는 ShowInfo() 즉, 선생정보출력을 호출함
schoolMemberPtr->ShowInfo(); // 다운캐스팅 : 부모에서 자식으로 내려가는 것
// Teacher의 형태로 형변환
((Teacher*)schoolMemberPtr)->ShowInfo();
*/
}
728x90
'돌다리도 두드려보고 건너라 <복만살>' 카테고리의 다른 글
[C++] 자료구조 종합 정리 (0) | 2022.06.27 |
---|---|
[C++] 내가 만든 선택지형 textRPG (0) | 2022.06.20 |
[C++] string / vector / vector+구조체 (0) | 2022.06.15 |
[C++] 배열/2차원배열/구조체/멤버함수/입력/랜덤 (0) | 2022.06.03 |
[C++] 출력/변수/지역성/조건문/연산자/반복문/함수/스택/포인터/배열 (0) | 2022.06.03 |