(C++)11장-3 가상함수의 이해

*업 캐스팅 시 참조형으로 받거나 포인터형으로 받을 때에도 함수 오버라이딩이 가능하다.
문법은 다음과 같다.

_________>상위 클래스 선언 안에서, virtual(함수 오버라이딩이 필요한 멤버 함수 선언부)

예제)
#define NAME_LEN 20

class Person
{
 protected:
  char name[NAME_LEN];
  int age;

public:
 Person(char* name,int age)
{
 strcpy_s(this->name,name);
 this->age=age;
}
virtual void introduce()  {  ///////상위클래스의 메소드에 virtual을 붙인다.
 cout<<"Person의 이름: "<<name<<endl;
 cout<<"Person의 나이: "<<age<<endl;
}

}

int main(void)
{
 Chulsoo chulsooUpRef=Chulsoo("철수",32,3);
 Person& personUpRef=chulsooRef;
 personUpRef.introduce();  //하위클래스의 introduce()호출 함
}

-->>그렇다면 모든 함수에 virtual 붙이면 되는 것이 아닐까? 맞다 그러면 된다.
하지만 CPU의 성능 혹은 메모리의 공간이 작았던 시절에는 virtual함수 하나하나가 오버헤드였다.

****소멸자에도 virtual키워드가 꼭 필요하다.*******

class Person{

protected:
 char* name;
 int age;

public:
  Person(char* name,int age)
{
  this->name=new char[strlen(name)+1];
  strcpy_s(this->name,strlen(name)+1,name);
  this->age=age;
  cout<<"생성자 호출"<<endl;
}
~Person(){

delete[] name;
}
virtual void introduce(){}
};


class Chulsoo: public Person
{
 private:
  char* bookName;
 public:
  Chulsoo(char* name,int age,char* bookName):Person(name,age)
{
 this->bookName=new char[strlen(bookName)+1];
 strycpy_s(this->bookName,strlen(bookName)+1,bookName);
 cout<<"철수 생성자"<<endl;
}
~Chulsoo()
{
 delete[] bookName;

}
void introduce(){}
}
}


int main(void)
{
 Person* personPtr=new Chulsoo("철수",32,"C++");
 personPtr->introduce();
 delete personPtr;
return 0;
}

-------------->Chulsoo객체를 Person의 포인터 변수로 업 캐스팅하고 introduce()를 함수 오버라이딩 한 후, 마지막으로 Chulsoo객체를 가리키는 Person포인터 변수인 personPtr을 해제한다.
당연히 Chulsoo객체의 소멸자가 호출될것이라 생각하지만, Person클래스의 소멸자만 호출 된다.
이를 위해 소멸자도 함수 오버라이딩 되어야한다.
즉, virtual ~Person(){}


-------------.>>이와같이 업캐스팅을 통해 다형성을 제공한다.


3.5 순수 가상함수와 추상 클래스의 이해

단순히 상위클래스에서는 메소드를 선언만하고 하위클래스에서 재정의하면 된다고 생각하지만 그러면 오류가난다
예를들어, person클래스에서
virtual void introduce();
virtual void eat();
virtual void sleep();
이러면 에러가 발생한다.
이럴 경우 순수가상함수 표시를 위해  =0을 붙인다.
virtual void introduce()=0;
virtual void eat()=0;

순수 가상함수를 하나 이상 포함한 클래스의 객체를 만들면 오류가 발생한다.
예)Person* person=new Person("사람",100);
이런 클래스를 추상클래스라 부른다. 이런 클래스는 상위클래스에 대한 객체 생성등이 굳이 필요 없을 때 사용한다.

4. 다중상속

만약 철수와 영희의 자식인 영철 클래스가 있다면 영철 클래스는 철수, 영희의 클래스를 상속받는다. 이를 다중상속이라 한다.

예)
class Youngchul: public Chulsoo, public Younghee
{
 public:
   Youngchul(): Chulsoo(), Younghee()
  {
     cout<<"영철 생성자 호출"<<endl;
  }

 ~Youngchul()
{

 cout<<"소멸자 호출"<<endl;

}

void write()
{
  //write();  //영희껀지 철수껀지 몰라 에러발생
   Chulsoo::write();  //철수의 wrtie()실행

}
}

--->> 생성자 생성 순서는 Person, Chulsoo, Younghee, Youngchul이다

4.1 다중 상속의 심화(가상 상속)
소멸자는 반대이다. 참고로 Person의 생성자와 소멸자는 두번씩 호출 된다. 이유는 Chulsoo,Younghee가 Person으로부터 상속 받기 때문이다.
문제는 10개가 상속 받는다면???????????/

그떄는
class Chulsoo : public virtual Person
{}을 하면 생성자,소멸자가 한번씩 호출된다.

또한 Person클래스에 sleep()함수를 정의하고 Chulsoo,Younghee클래스에는 정의하지 않았다고 하자. 그때 Youngchul youngchul;
youngchul.sleep()를 호출하면 에러가 난다. 이유는 Person클래스로 접근하는게 두개 이므로 어느것인지 몰라 에러가난다. 이떄도 똑같이 가상상속을 한다.

class Chulsoo:public virtual Person{}
class Younghee : public virtual Person{}

댓글

이 블로그의 인기 게시물

(ElasticSearch) 결과에서 순서 정렬

(네트워크)폴링방식 vs 롱 폴링방식

(18장) WebSocekt과 STOMP를 사용하여 메시징하기