티스토리 뷰
08-1: 객체 포인터의 참조관계
객체 포인텨 변수: 객체의 주소 값을 저장하는 포인터 변수
Person*ptr ;// 변수 선언
ptr=new Person() // 참조선언
Person형 포인터는 Person 객체 뿐만 아니라 유도 클래스의 객체도 가리킬 수 있다.
class Student: public Person
{
};
Person *ptr =new Students();
class PartTimeStudent: public Student
{
};
C++에서 ,AA형 포인터 변수는 AAA 객체 또는 AAA를 직접 혹은 간접적을 ㅗ상속하는 모든 객체를 가리킬 수 있다.(객체의 주소값을 저장할 수 있다.)
유도클래스의 객체까지 가리킬 수 있다니!
IS-A 관게를 통해 이해할 수 있다.
학생은 사람이다.
근로학생은 학생이다.
근로학생은 사람이다.
오렌지미디어 급여관리 확장성 문제의 1차적 해결과 함수 오버라이딩
고용인 Employee
정규직 PermanentWorker
영업직 SalesWorker
임시직 TemporaryWorketr
'EmployeeHandler 클래스가 저장 및 관리하는 대상이 Employee 객체가 되게 하면 이후에 Employee 클래스를 직접 혹은 간접적으로 상속하는 클래스가 추가되었을 때, EmployeeHandler 클래스에는 변화가 생기지 않는다.
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
using namespace std;
class Employee
{
private:
char name[100];
public:
Employee(char* name)
{
strcpy(this->name, name);
}
void ShowYourName() const
{
cout << "name: " << name << endl;
}
};
class PermanentWorker : public Employee
{
private:
int salary;
public:
PermanentWorker(char*name,int money)
:Employee(name),salary(money)
{}
int GetPay() const
{
return salary;
}
void ShowSalaryInfo() const
{
ShowYourName();
cout << "salary: " << GetPay() << endl << endl;;
}
};
class EmployHandler
{
private:
Employee* empList[50];
int empNum;
public:
EmployHandler():empNum(0)
{}
void addEmployee(Employee* emp)
{
empList[empNum++] = emp;
}
void ShowAllSalaryInfo() const
{
/*
for(int i=0; i<empNum;i++)
empList[i]->ShowSalaryInfo();
*/
}
void ShowTotalSalary() const
{
int sum = 0;
/*
for(int i=0;i<empNum;i++)
sum+=empList[i]->GetPay();
*/
}
~EmployHandler()
{
for (int i = 0; i < empNum; i++)
delete empList[i];
}
};
int main(void)
{
EmployHandler handler;
handler.addEmployee(new PermanentWorker("KIM", 1000));
handler.addEmployee(new PermanentWorker("LEE", 1500));
handler.addEmployee(new PermanentWorker("JUN", 2000));
handler.ShowAllSalaryInfo();
handler.ShowTotalSalary();
return 0;
}
함수 오버라이딩
유도클래스에도 기초클래스에 동일한 이름의 함수를 정의하는 것.
08-2 가상함수(Virtual Function)
class Base
{};
class Derived : public Base
{
void DerivedFunc()
{}
};
이 떄 포인터 참조연산을 하면
Base*bptr = new Derived(); //컴파일 OK
bptr->DerivedFunc(); //컴파일 에러;
-> Base형이기에 컴파일이 안된다.
Base*bptr = new Derived(); //컴파일 OK
Derived*dptr=bptr; //컴파일에러
컴파일러는 bptr이 Derived 객체라는 것을 기억하지 않고 에러를 일으킨다.
int main(void}
{
Derived*dptr=new Derived(); //컴파일 OK
Base*bptr=dptr; //컴파일 OK
}
Derived 클래스의 포인터 변수니까 Base 포인터 변수로 참조가 가능하다.
위에서 한 이야기의 복습
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
using namespace std;
class First
{
public:
void FirstFunc()
{
cout << "FirstFunc" << endl;
}
};
class Second: public First
{
public:
void SecondFunc()
{
cout << "SecondFunc" << endl;
}
};
class Third:public Second
{
public:
void ThirdFunc()
{
cout << "ThirdFunc" << endl;
}
};
int main(void)
{
Third* tptr = new Third();
Second* sptr = tptr;
First* fptr = sptr;
}
tptr->FirstFunc(); (O)
tptr->SecondFunc(); (O)
tptr->ThirdFunc(); (O)
sptr -> FirstFunc(); (O)
sptr-> SecondFunc(); (O)
sptr->ThirdFunc(); (X)
fptr->FirstFunc(); (O)
fptr->SecondFunc;(X)
fptr->SecondFunc;(X)
결론적으로포인터 형에 해당하는 클래스에 정의된 멤버에만 접근이 가능하다.
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
using namespace std;
class First
{
public:
void MyFunc()
{
cout << "FirstFunc" << endl;
}
};
class Second: public First
{
public:
void MyFunc()
{
cout << "SecondFunc" << endl;
}
};
class Third:public Second
{
public:
void MyFunc()
{
cout << "ThirdFunc" << endl;
}
};
int main(void)
{
Third* tptr = new Third();
Second* sptr = tptr;
First* fptr = sptr;
fptr->MyFunc();
sptr->MyFunc();
tptr->MyFunc();
return 0;
}
함수 이름이 같더라도 First 쓰면 First 호출되고 Second하면 Second가 호출된다.
가상함수(Virtual Function)
함수를 오버라이딩 했다는 것은 해당 객체에서 호출되어야 하는 함수를 바꾼다는 의미인데, 포인터 변수의 자료형에 따라서 호출되는 함수의 종류가 달라지는 것은 문제가 있어보인다.
-> 포인터의 형에 상관 없이 포인터가 가리키는 객체의 마지막 오버라이딩 함수를 호출한다.
class First
{
public:
virtual void MyFunc() {}
}
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
using namespace std;
class First
{
public:
virtual void MyFunc()
{
cout << "FirstFunc" << endl;
}
};
class Second: public First
{
public:
virtual void MyFunc()
{
cout << "SecondFunc" << endl;
}
};
class Third:public Second
{
public:
virtual void MyFunc()
{
cout << "ThirdFunc" << endl;
}
};
int main(void)
{
Third* tptr = new Third();
Second* sptr = tptr;
First* fptr = sptr;
fptr->MyFunc();
sptr->MyFunc();
tptr->MyFunc();
return 0;
}
오렌지미디어 급여관리 확장성 문제의 해결을 통해서 확인한 상속의 이유
'상속을 하는 이유는 무엇인가?'
-> 상속을 통해 연관된 일련의 클래스에 대해 공통적인 규약을 정의할 수 있습니다.
순수 가상함수(Pure Virtual Function)와 추상 클래스(Abstract Class)
몸체가 정의되지 않은 함수를 순수 가상함수라고 한다.
하나의 순수 가상함수를 멤버로 두어서 객체 생성을 불가능하게 한 것을 추상클래스라고 한다.
다형성(Polymorphism)
모습은 같은데 형태는 다르다.
문장은 같은데 결과는 다르다
08-3 가상 소멸자와 참조자의 참조 가능성
가상 소멸자(Virtual Destructor)
기초클래스의 소멸자를 호출하면, 유도 클래스의 소멸자도 호출해야한다.
그러나 virtual로 선언해서 유도클래스 소멸자를 호출하면 자동으로 기초 클래스의 소멸자도 호출된다.
효율적인 코드를 위해 사용된다.
참조자의 참조 가능성
포인터 뿐만 아니라 참조자도 사용할 수 있다.
First 참조자를 쓰면 First 클래스에 정의된 MyFunc가 호출되고, Second면 Second 호출, Third면 Third가 호출된다.
'프로그래밍 > 윤성우의 열혈 C++' 카테고리의 다른 글
Chapter 11 연산자 오버로딩 2 (0) | 2022.03.14 |
---|---|
Chapter 09 가상(virtual)의 원리와 다중상속 (0) | 2022.03.12 |
Chapter 07 상속(Inheritance)의 이해 (0) | 2022.03.09 |
Chapter 06 friend와 static 그리고 const (0) | 2022.03.08 |
05 복사생성자(copy constructor) (0) | 2022.03.07 |
- Total
- Today
- Yesterday
- 심리학
- Python
- 인프런
- 인지부조화
- K-MOOC
- c++
- 코딩테스트
- C
- 강화학습
- 통계
- 데이터분석
- C/C++
- 오블완
- 티스토리챌린지
- 윤성우
- 회계
- 보세사
- 일본어
- 여인권
- stl
- 통계학
- 정보처리기사
- 사회심리학
- 백준
- 류근관
- 일문따
- 열혈프로그래밍
- 일본어문법무작정따라하기
- 뇌와행동의기초
- 파이썬
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |