<내가돈주고산열혈강의C++ ppt자료에서 캡춰>
<내가돈주고산열혈강의C++ ppt자료에서 캡춰>
using std::endl;
public:
void Swing(){cout<<"Swing a codgel"<<endl;}
};
{
Cudgel cud;
public:
void UseWeapon(){cud.Swing();}
};
int main()
{
Police pol;
pol.UseWeapon();
return 0;
}
Cudgel클래스의 객체가 Police의 멤버객체로 포함되어있다..이러한 객체를 클래스 객체멤버
혹은 객체멤버라고 한다. 이러한 관계를 포함관계라고 한다.
상속과 포함관계 둘로 나타낼수 있을때에는 상속보다 포함관계를 쓰는편이 좋다.
왜냐면 그것은 결합도의 문제인데 결합도가 높아질수록 혹시모르는 변경을 할때
결합도가 높을수록 코드를 손봐야 할 부분이 많아진다.
상속관계는 결합도가 포함관계보다 높다.
2. 상속된 객체와 포인터와의 관계
객체포인터 : 객체의 주소값을 저장할수 있는 포인터.
A클래스의 포인터 A*는 A객체의 주소값 뿐만 아니라 A클래스를 상속하는 Derived클래스 객체의 주소값도 저장이 가능하다. 여기서 A클래스의 포인터를 가리켜 객체포인터라고 한다
Student클래스는 Person클래스를 상속하고 PartTimeStd클래스는 Student클래스를 상속한다
이런 상속관계의 경우 PartTimeStd가 Student를 상속하고.Student가 Person을 상속하고
PartTimeStd객체가 객체안에 Student객체와 Person객체를 상속하고 있으므로
PartTimeStd객체는 Student객체이자 Person객체이고 Student객체는 Person객체이다.
그러므로 Person포인터 Student포인터 PartTimeStd포인터로 PartTimeStd객체를 가리키는
것은 아무런 문제가 없다..
그러나 가리키는 것만 문제가 없을뿐..각각의 포인터의 권한은 다르다..
그림에서 보면 Student나 Person포인터는 각각 상속하고 있는 객체를뚫고 가리키고있다
뚫고 지나간 객체는 뚫고지나는 포인터로 항상 가리킬수 있다.(이결론내느라 빡셌다)
그리고 위의 그림에서 보면 각 포인터의 권한은 포인터가 가리키고 있는 객체안에 상속된
객체까지만 접근이 가능하다. Person*로 Student나 PartTimeStd객체에 접근(여기서 접근이란 객체의 컨트롤)이 불가능 하다 Person*는 Person객체만 접근 가능하고
Student*는 Student와상속하는Person객체, PartTimeStd*는 상속하는Student와Person객체
모두 접근가능하다.
3. 객체레퍼런스
객체레퍼런스는 객체포인터의 내용과 일치한다.
4. Static Binding & Dynamic Binding
오버라이딩의 이해
#include <iostream>
using std::cout;
using std::endl;
class AAA{
public:
void fct(){
cout<<"AAA"<<endl;
}
};
class BBB : public AAA{
public:
void fct(){
cout<<"BBB"<<endl;
}
};
int main(){
BBB b;
b.fct();
return 0;
}
Base클래스에서 선언한 멤버함수를 Derived클래스에서 또다시 선언하면?
이것의 형태를 가리켜 오버아리딩(overriding)이라고 한다. 오버라이딩은 이전에 정의된
함수를 가리는 특성이 있다.
위의 예제에서 BBB클래스의 객체b를 생성하려고 들어갔더니 어.AAA를 상속하네
AAA로 ㄱㄱ 갔더니 fct함수가 있네.어?근데BBB에도 fct함수가 있네..그럼 AAA멤버함수 실행
안하고 바로 BBB멤버함수 실행한다.객체생성완료..
그런데 오버라이딩된 함수는 호출이 불가능할까? 가능하다.대한민국에불가능한게어딨어.
int main(){
BBB* b = new BBB;
b->fct();
AAA* a=b;
a->fct();
delete b;
return 0;
}
이렇게 포인터로 접근을 하면 오버라이딩된 함수에도 접근이 가능하다.
이 예문은 위에 js의 그림판 그림들을 보면서 이해하도록. ㅋㅋㅋㅋㅋㅋㅋ저그림예술이야.
멤버함수 virtual 으로 선언하기
class AAA{
public:
virtual void fct(){
cout<<"AAA"<<endl;
}
};
class BBB : public AAA{
public:
void fct(){
cout<<"BBB"<<endl;
}
};
멤버함수에 virtual 키워드를 붙이면 이것은 가상의 함수..즉 없는 함수가 된다.
있지만 없는 함수-_-;
int main(){
BBB* b = new BBB;
b->fct();
AAA* a=b;
a->fct();
delete b;
return 0;
}
이렇게 할경우 둘다 BBB의 함수만 호출한다.왜? 없는 함수니까 AAA의 멤버함수는.
여기서 주의할점.
함수 이름이 같아야 Virtual 선언이 먹힌다
virtual 키워드가 붙지 않은 상태의 오버라이딩은 은닉이다.
오버라이딩이라고 무조건 재정의가 아님.
class AAA{
public:
virtual void fct(){
cout<<"AAA"<<endl;
}
};
class BBB : public AAA{
public:
virtual void fct(){
cout<<"BBB"<<endl;
}
};
class CCC : public BBB{
public:
virtual void fct(){
cout<<"CCC"<<endl;
}
};
최종적으로 오버라이딩한 함수를 제외한 나머지 함수는 가려지게 된다.
오버라이딩된 함수 호출하기
#include <iostream>
using std::cout;
using std::endl;
class AAA{
public:
virtual void fct(){
cout<<"AAA"<<endl;
}
};
class BBB : public AAA{
public:
void fct(){
AAA::fct();
cout<<"BBB"<<endl;
}
};
int main(){
AAA* a=new BBB;
cout<<"첫번째 시도"<<endl;
a->fct();
cout<<"두번째 시도"<<endl;
a->AAA::fct(); //거의 사용안함..쓰지마
return 0;
}
오버라이딩 된 함수도 범위지정연산자 ( :: )를 이용하여 호출이 가능하다.
그러나 두번째껀 쓰지말래..쓰고싶지도않아 ㅎ;;
순수가상함수와 추상클래스
class AAA{
public:
virtual void fct(){
cout<<"AAA"<<endl;
}
};
class BBB : public AAA{
public:
virtual void fct(){
cout<<"BBB"<<endl;
}
};
public:
virtual void fct(){
cout<<"CCC"<<endl;
}
};
위의 예제에서 AAA클래스의 멤버함수 fct는 아무런 기능을 하지 않는다 가상이니까
그때는 순수가상함수로 만들어줄수있다 바로..
public:
virtual void fct()=0;
};
요딴식으로 말이지..이런식의 함수를 가리켜 순수 가상함수라고 한다.
이건 가상함수와 달라서 아예 없는함수다 가상함수는 있으면서 없는 함수지만 이건 아예 없는 함수이다.
저렇게 하나이상의 멤버함수가 순수가상함수인 클래스를 가리켜 추상클래스 라고한다.
추상클래스는 객체화 하지못한다.함수의 정의가 생략되었기때문에 완전한 클래스가 아니므로 객체를 생성할수 없다.
5. virtual 소멸자의 필요성
#include <iostream>
using std::cout;
using std::endl;
class AAA{
char* str1;
public:
AAA(char* _str1){
str1 = new char[strlen(_str1)+1];
strcpy(str1,_str1);
}
~AAA(){
cout<<"~AAA() call"<<endl;
delete []str1;
}
virtual void ShowString(){
cout<<str1<<endl;
}
};
class BBB : public AAA{
char* str2;
public:
BBB(char* _str1,char* _str2) : AAA(_str1){
str2 = new char[strlen(_str2)+1];
strcpy(str2,_str2);
}
~BBB(){
cout<<"~BBB() call"<<endl;
delete []str2;
}
virtual void ShowString(){
AAA::ShowString();
cout<<str2<<endl;
}
};
int main(){
AAA* a=new BBB("Good","evening");
BBB* b=new BBB("Good","morning");
a->ShowString();
b->ShowString();
cout<<"객체소멸직전"<<endl;
delete a;
delete b;
return 0;
}
위의 예제의 문제점..
위의 예제 AAA객체의 소멸자에
cout<<"~AAA() call"<<endl;
delete []str1;
}
짜잔..저렇게 된다.근데 좀 이상해..두개의 소멸자는 이름이 다른데 AAA소멸자가 virtual선언이 되어있다고 해서 BBB의 객체 소멸자를 대신 호출하냐고..음..저거는 이름은 다르지만
둘다 소멸자인 관계로 virtual함수를 오버라이딩 했을때의 현상이 그대로 적용이된다.
(근데 저거 무한루프아니여?ㅋㅋ)