C++ 10-2

BakJeonghyun·2022년 11월 1일
0

전공C++

목록 보기
19/20

C++에서는 파생 클래스에 기본 클래스의 멤버 함수와 동일한 이름과 원형으로 함수를 재정의(redefine)하여 사용할 수 있다. 예제 9-1은 파생 클래스에서 함수 f()를 재정의한 사례이다. 예제 9-1을 통해 함수 재정의의 의미를 알아보자.

9-1 파생 클래스에서 함수를 재정의하는 사례

[실행 결과]

Derived::f() called
Base::f() called
#include <iostream>
using namespace std;

class Base {
public:
	void f() {cout << "Base::f() called" << endl;}
};

class Derived : public Base {
public:
	void f() {cout << "Derived::f() called" << endl;} // Base의 멤버 함수 f()를 재정의
};

void main() {
	Derived d, *pDer;
    pDer = &d; // 객체 d를 가리킨다.
    pDer->f(); // Derived의 멤버 f() 호출
    
    Base* pBase;
    pBase = pDer; // 업캐스팅. 객체 d를 가리킨다.
    pBase->f(); // Base의 멤버 f() 호출
}

pDer이 가리키는 객체에는 두 개의 f() 함수가 있지만, 컴파일러는 파생 클래스의 함수를 우선적으로 바인딩하기 때문이다. 다음 코드는 업 캐스팅을 통해 pBase가 객체 d를 가리킨다. pBase로 함수 f()를 호출하면 어떤 결과가 나타나게 될까?

pBase = pDer; // 업 캐스팅. pBase는 객체 d를 가리킨다.
pBase->f(); // Base의 멤버 f() 호출

pBase가 Base 클래스에 대한 포인터이므로 컴파일러는 Base의 멤버 f() 함수를 호출하도록 컴파일한다. 그 결과 그림과 같이 Base의 f() 함수를 호출한다.


9-3

#include <iostream>
using namespace std;

class Base {
public: virtual void f() {cout << "Base::f() called" << endl;}
};

class Derived : public Base {
public: void f() {cout << "Derived::f() called" << endl;}
};

class GrandDerived : public Derived {
public: void f() {cout << "GrandDerived::f() called" << endl;}
};

int main() {
	GrandDerived g;
    Base *bp;
    Derived *dp;
    GrandDerived *gp;
}

9-4

#include <iostream>
using namespace std;

class Shape {
public:
	virtual void draw() {
    	cout << "--Shape--";
    }
};

class Circle : public Shape {
public:
	int x;
    virtual void draw() {
    	Shape::draw(); // 기본 클래스의 draw() 호출
        cout << "Circle" << endl;
    }
};

int main() {
	Circle circle;
    Shape * pShape = &circle;
    
    pShape->draw(); // 동적 바인딩 발생. draw()가 virtual이므로
    pShape->Shape::draw(); // 정적 바인딩 발생. 범위 지정 연산자로 인해
}

9-5

#include <iostream>
using namespace std;

class Base {
public: 
	virtual ~Base() {cout << "~Base()" << endl;}
};

class Derived: public Base {
Public:
	virtual ~Derived() {cout << "~Derived()" << endl;}
};

int main() {
	Derived *dp = new Derived();
    Base *bp = new Derived();
    
    delete dp; // Derived의 포인터로 소멸
    delete bp; // Base의 포인터로 소멸
}

9-6 추상 클래스 구현 연습

다음과 같은 추상 클래스 Calculator가 있다고 할 때 이를 상속받은 GoodCalc 클래스를 구현하라.

class Calculator {
public:
	virtual int add(int a, int b) = 0; // 두 정수의 합 리턴
    virtual int subtract(int a, int b) = 0; // 두 정수의 차 리턴
    virtual double average(int a [], int size) = 0; // a의 평균 리턴, size는 배열 크기
};

Calculator는 계산기가 제공해야 하는 기능을 정의하고 있다고 볼 수 있다. GoodCalc는 Calculator에 선언된 3개의 순수 가상 함수를 모두 구현하여야 한다. GoodCalc 클래스와 이를 활용하는 main() 함수는 다음과 같다.

#include <iostream>
using namespace std;

class Calculator {
public:
	virtual int add(int a, int b) =0;
    virtual int subtract(int a, int b) =0;
    virtual double average(int a[], int size) =0;
};

class GoodCalc : public Calculator {
public:
	int add(int a, b) {return a+b;}
    int subtract(int a, b) {return a-b;}
    double average(int a[], int size) {
    	double sum = 0;
    	for (int i=0; i<size; i++) {
        	sum +=a[i];
        }
        return sum / size;
    }
}; // private 빼고 다 public으로 가져옴

int main() {
	int a[] = {1,2,3,4,5};
    Calculator *p = new GoodCalc(); // 동적 할당
    cout << p->add(2,3) << endl;
    cout << p->subtract(2,3) << endl;
    cout << p->average(a,5) << endl;
    delete p;

}


9-7 추상 클래스를 상속받는 파생 클래스 구현 연습

다음 코드와 실행 결과를 참고하여, 추상 클래스 Calculator를 상속받는 Adder와 Subtractor 클래스를 구현하라.

[실행 결과]

정수 2 개를 입력하세요>> 5 3
계산된 값은 8
정수 2 개를 입력하세요>> 5 3
계산된 값은 2
#include <iostream>
using namespace std;

class Calculator {
private:
	void input() {
    	cout << "정수 2 개를 입력하세요>> ";
        cin >> a >> b;
    }
protected:
	int a, b;
    virtual int calc(int a, int b) = 0; // 두 정수의 합 리턴
public:
	void run() {
    	input();
        cout << "계산된 값은 " << calc(a,b) << endl;
    }
}

int main() {
	Adder adder;
    Subtractor subtractor;
    
    adder.run();
    subtractor.run();
}
profile
I just got started a blog.

0개의 댓글