가상함수가 쓰이는 시기는 언제인가. ???
Shape 클래스와 자식 클래스들.
책 페이지 667 의 코드[단일 실행이 가능함]
책 내의 코드 우측에 쓰여있는 문장이나 굵은 글씨로 된 것 들을 모아두었다.
이 코드는 가상함수가 쓰인것이 아니다.
클래스가 3개나 있어서 코드가 꽤나 길지만 뭐 복잡한 부분은 없고 3개의 클래스가 있고
Shape 클래스에 2개의 도형이 들어간다.
멤버 변수의 경우에는 부모 클래스로부터 상속 받은 것을 그대로 사용할 수 밖에 없지만 멤버 함수의 경우에는 부모 클래스에서 구현한 것이 맘에 들지 않는다면 자기에게 맞도록 새롭게 정의할 수 있다.
Draw()함수가 바로 그런 예 이다.
보관한 객체를 사용하는것과 그에 따른 문제점.
예제 코드
위의 코드에서 int main() 쪽만 내용이 다른 코드이다.
출력화면
이 소스코드를 보면 상속을 사용하는 것이 얼마나 편한지를 알 수 있다. 하지만 위의 출력화면 을 보면 이 예제에 문제가 있다는 것을 알 수 있다.
모든 줄의 출력이 [Shape]라는 문자열로 시작하는것이 문제인데. 이는 Shape::Draw() 함수를 호출했다는 뜻이다.
즉 이 위의 코드나 바로 위의 출력화면이 나오는 코드나 둘 다 잘못되었다는 것이다.
바로 지금! 이러한 문제가 발생할 때에 가상함수가 필요하다.
허탈하고 간단하게도 코드를 약간만 수정하여 가상함수를 사용하면 쉽게 이 문제를 풀 수 있다.
이 코드에서
void Draw() const; //모든 도형 클래스들은 자신을 움직이거나, 그리는 함수가 필요하다.
를
virtual void Draw() const;
로 바꾼뒤에 출력을 해보면 다음과 같은 출력화면이 나올 것이다.
Shape::Draw 함수를 가상함수로 만들면 Circle::Draw와 Rectangle::Draw 함수 역시 자동적으로 가상함수가 된다.
또한 cirtual 키워드는 클래스의 정의 안쪽에서만 한 번 붙여주면 된다. 클래스 밖에서 함수를 정의할 때는 virtual 키워드가 필요 없다.
최종 출력화면을 나타내는 코드 파일 업로드.
Shape 클래스와 자식 클래스들.
책 페이지 667 의 코드[단일 실행이 가능함]
책 내의 코드 우측에 쓰여있는 문장이나 굵은 글씨로 된 것 들을 모아두었다.
이 코드는 가상함수가 쓰인것이 아니다.
클래스가 3개나 있어서 코드가 꽤나 길지만 뭐 복잡한 부분은 없고 3개의 클래스가 있고
Shape 클래스에 2개의 도형이 들어간다.
멤버 변수의 경우에는 부모 클래스로부터 상속 받은 것을 그대로 사용할 수 밖에 없지만 멤버 함수의 경우에는 부모 클래스에서 구현한 것이 맘에 들지 않는다면 자기에게 맞도록 새롭게 정의할 수 있다.
Draw()함수가 바로 그런 예 이다.
보관한 객체를 사용하는것과 그에 따른 문제점.
예제 코드
위의 코드에서 int main() 쪽만 내용이 다른 코드이다.
int main()
{
// 도형들을 담을 배열을 준비한다
Shape* shapes[5] = {NULL}; // Shape* 타입의 배열을 준비한다.[포인터 배열]
// 각 타입의 객체를 생성해서 배열에 보관한다.
shapes[0] = new Circle( 100, 100, 50);
shapes[1] = new Rectangle( 300, 300, 100, 100);
shapes[2] = new Rectangle( 200, 100, 50, 150);
shapes[3] = new Circle(100, 300, 150);
shapes[4] = new Rectangle( 200, 200, 200, 200); //여러가지 타입의 객체를 동적으로 생성한
//뒤에 반환되는 포인터를 배열에 보관한다.
//뒤에 반환되는 포인터를 배열에 보관한다.
// 배열의 보관된 모든 객체를 그린다.
for (int i = 0; i < 5; ++i)
shapes[i]->Draw(); //반복문을 사용하여 모든 원소에 대한 Draw() 멤버함수를 호출한다.
// 배열의 보관된 모든 객체를 소멸시킨다.
for (int i = 0; i < 5; ++i)
{
delete shapes[i];
shapes[i] = NULL; //반복문을 통해 값을 삭제 하고 NULL로 채워준다.
}
system("pause"); //디버깅시에 그냥 출력창이 꺼지는것을 방지하기 위한 코드.
return 0;
}
출력화면
for (int i = 0; i < 5; ++i)
shapes[i]->Draw(); //반복문을 사용하여 모든 원소에 대한 Draw() 멤버함수를 호출한다.
라는 2줄의 코드 만으로 배열에 저장된 모든 객체에 대해서 Draw함수를 호출하고 있다. 이것이 상속의 장점이다.
하지만 만약 도형 클래스들이 수십개 있고 또 클래스마다 배열을 따로 만들어서 관리했다면 Draw함수를 호출하는 코드도 많아지게 될 것이다.
다음 코드를 보자.[프로그램 코드에 넣는게 아니고 그냥 보기만 하자]
라는 2줄의 코드 만으로 배열에 저장된 모든 객체에 대해서 Draw함수를 호출하고 있다. 이것이 상속의 장점이다.
하지만 만약 도형 클래스들이 수십개 있고 또 클래스마다 배열을 따로 만들어서 관리했다면 Draw함수를 호출하는 코드도 많아지게 될 것이다.
다음 코드를 보자.[프로그램 코드에 넣는게 아니고 그냥 보기만 하자]
이 소스코드를 보면 상속을 사용하는 것이 얼마나 편한지를 알 수 있다. 하지만 위의 출력화면 을 보면 이 예제에 문제가 있다는 것을 알 수 있다.
모든 줄의 출력이 [Shape]라는 문자열로 시작하는것이 문제인데. 이는 Shape::Draw() 함수를 호출했다는 뜻이다.
즉 이 위의 코드나 바로 위의 출력화면이 나오는 코드나 둘 다 잘못되었다는 것이다.
바로 지금! 이러한 문제가 발생할 때에 가상함수가 필요하다.
허탈하고 간단하게도 코드를 약간만 수정하여 가상함수를 사용하면 쉽게 이 문제를 풀 수 있다.
class Shape
{ //Shape 클래스의 정의, 원 , 사각형 같은 일반적인 도형들이
public: //공통적으로 가지는 속성들을 여기에 정의한다. 자식 클래스들은
void Move(double x, double y); //이 멤버들을 자동적으로 상속받게 된다.//
void Draw() const; //모든 도형 클래스들은 자신을 움직이거나, 그리는 함수가 필요하다.
이 코드에서
void Draw() const; //모든 도형 클래스들은 자신을 움직이거나, 그리는 함수가 필요하다.
를
virtual void Draw() const;
로 바꾼뒤에 출력을 해보면 다음과 같은 출력화면이 나올 것이다.
Shape::Draw 함수를 가상함수로 만들면 Circle::Draw와 Rectangle::Draw 함수 역시 자동적으로 가상함수가 된다.
또한 cirtual 키워드는 클래스의 정의 안쪽에서만 한 번 붙여주면 된다. 클래스 밖에서 함수를 정의할 때는 virtual 키워드가 필요 없다.
최종 출력화면을 나타내는 코드 파일 업로드.
**공부에 도움이 되었다면 손가락 버튼을 클릭해주심 좋겠습니다.**
'공부 > C++' 카테고리의 다른 글
콤보박스 사용 함수. GetLBText (0) | 2011.12.29 |
---|---|
C++ 객체지향 프로그래밍 Chapter 22 상속과 포함 - 2 (0) | 2011.12.20 |
C++ 객체지향 프로그래밍 Chapter 22 상속과 포함 (0) | 2011.12.16 |
C++ 객체지향 프로그래밍 Chapter 21 클래스와 객체 - 2 (0) | 2011.12.15 |
C++ 객체지향 프로그래밍 Chapter 21 클래스와 객체 (0) | 2011.12.15 |