C/C++ 관련 헷갈리기 쉬운 것 정리5(저장용,메모용, 윤성우 열혈 C++ 프로그래밍 정리 CH 8)

RisingJade의 개발기록·2022년 2월 21일
0

Chapter 08. 상속과 다형성


08-1. 객체포인터 참조개체

1. 객체 포인터 변수: 객체의 주소 값을 저장하는 포인터 변수

  • 클래스 기반으로도 포인터 변수를 선언가능

    Person * ptr;
    ptr = new Person();

  • 위에서 Person형 포인터는 Person 객체뿐만 아니라, Person을 상속하는 유도 클래스의 객체도 가리킬 수 있다.

    "C++에서, AAA형 포인터 변수는 AAA 객체 또는 AAA를 직접 혹은 간접적으로 상속하는 모든 객체를 가리킬 수 있다. (객체의 주소 값을 저장할 수 있다.)"

2. 확장성 문제 해결과 함수 오버라이딩

  • 기초 클래스에 정의되어있는 함수가 유도 클래스에서 동일한 이름과 형태로 정의된다면 이를 가르켜 함수 오버라이딩이라 한다.

08-2. 가상 함수(Virtual Function)

기초 클래스의 포인터로 객체를 참조하면,

C++ 컴파일러는 포인터 연산의 가능성 여부를 판단 할 때, 포인터의 자료형을 기준으로 판단하지, 실제 가리키는 객체의 자료형을 기준으로 판단하지 않는다.

  • 기초 클래스 포인터변수에 담긴(가리켜지는) 객체는 기초 클래스가 가진 기능만 이용 할 수 있다. 또한 원래 자신의 클래스인 유도클래스의 포인터에 다시 담기지 않는다. 왜냐하면 컴파일러 입장에선 현재 기초 클래스 포인터변수가 가지고 있는 객체가 Base객체인지 유도 객체인지 알 방법이 없기 때문에 Base 객체라 가정하고 Base객체는 유도클래스 객체에 담길 수 없으므로 컴파일 에러를 내 뱉는다.

함수의 오버라이딩과 포인터 형

  • 상속 되고 오버라이딩 된 함수가 있다면, 현재 클래스 포인터에 맞는 오버라이딩 함수 혹은 오버라이딩이 되지 않았으면

가상함수

  • 함수가 가상함수(virtual) 선언이 되면, 이를 오버라이딩하는 함수도 가상함수가 된다.(별도로 virtual 키워드를 추가하지 않아도 가상함수가 된다)
  • 함수가 가상함수로 선언이 되면, 해당 함수호출 시, 포인터의 자료형을 기반으로 호출대상을 결정하지 않고, 포인터 변수가 실제로 가리키는 객체를 참조하여 호출의 대상을 결정한다.

TIP

  • '오랜지 미디어 급여관리 확장성 문제'의 해결을 통해서 확인한 상속의 이유
    • 상속을 통해 연관된 일련의 클래스 PermanentWorker, TemporaryWorker, SalesWorker에 공통적인 규약을 정의할 수 있다.

순수 가상함수(Pure Virtual Function)와 추상 클래스(Abstract Class)

  • 클래스 중에서는 객체생성을 목적으로 정의되지 않는 클래스도 존재한다.
  • 그러한 목적의 class들은 가상 함수를 '순수 가상함수'로 선언하여 객체의 생성을 문법적으로 막는것이 좋다.

    순수 가상함수란? 함수의 몸체가 정의되지 않는 함수.
    이를 표현하기 위해 '0의 대입'을 표시한다. 이는 '명시적으로 몸체를 정의하지 않았음'을 컴파일러에게 알리는 것이다.

  • 이렇듯 하나 이상의 멤버함수를 순수 가상함수로 선언한 클래스를 가리켜 '추상 클래스'라고 한다. 이는 완전하지 않는, 그래서 객체생성이 불가능한 클래스라는 의미를 지닌다.

다형성(Polymorphism)

  • 방금 설명한 가상함수의 호출관계에서 보인 특성을 가리켜 '다형성'이라 한다.
  • "모습은 같은데 형태는 다르다" 즉, "문장은 같은데 결과는 다르다!"
class First {
public:
	virtual void SimpleFunc() { cout << "First" << endl; }
};

class Second : public First {
public:
	virtual void SimpleFunc() { cout << "Second" << endl; }
};

int main(void){
	First* ptr = new First();
	ptr->SimpleFunc(); // First 출력
	delete ptr;

	ptr = new Second(); // Second 출력
	ptr->SimpleFunc();
    delete ptr;
    ...
}

위와 같이 ptr->SimpleFunc()이라는 문장은 같은데 출력이 "First"랑 "Second"로 다르게 나온다.


08-3. 가상 소멸자와 참조자의 참조 가능성

가상 소멸자 (Virtual Destructor)

  • 객체의 소멸을 기초 클래스의 포인터로 명령하면 기초클래스의 소멸자만 호출된다. 이와 같은 경우 메모리의 누수가 발생할 수 있다. 따라서 객체의 소멸과정에서는 delete 연산자에 사용된 포인터 변수의 자료형에 상관없이 모든 소멸자가 호출되어야 한다.
  • 가상함수와 마찬가지로 소멸자도 상속의 계층구조상 맨 위에 존재하는 기초 클래스의 소멸자만 virtual로 선언하면, 이를 상속하는 유도 클래스의 소멸자들도 모두 '가상 소멸자'로 선언이 된다. (별도로 virtual 키워드를 추가하지 않아도 가상 소멸자가 된다)
  • 가상 소멸자가 호출되면, 상속의 계층구조상 맨 아래에 존재하는 유도 클래스의 소멸자가 대신 호출되면서, 기초 클래스의 소멸자가 순차적으로 호출된다.

참조자의 참조 가능성

C++에서, AAA형 참조자는 AAA객체 또는 AAA를 직접 혹은 간접적으로 상속하는 모든 객체를 참조할 수 있다.

profile
언제나 감사하며 살자!

0개의 댓글