클래스 상속 (2)

SOEUN CHOI·2022년 5월 31일
0

C++_study

목록 보기
6/15
post-thumbnail

씹어먹는 C++

7장 클래스의 상속 298p - 339p


상속의 관계

장점

  • 추상화
  • 특수화
  • 일반화
  • 다형성
    하나의 메소드를 호출했음에도 불구하고 여러가지 다른
    작업들을 수행

is - a / has - a

is - a / has - a
모든 상속 관계
뒤 바꾸면 성립 안됨
기반 클래스의 모든 기능을 파생 클래스가 포함
파생 is a 기반

up casting

파생 클래스에서 기반 클래스로 캐스팅 하는 것

example code

class Base {
	std::string s;
	
    public:
		Base() : s("기반") { std::cout << "기반 클래스" << std::endl; }
		void what() { std::cout << s << std::endl; }
};

class Derived : public Base {
	std::string s;
	
    public:
		Derived() : s("파생"), Base() { std::cout << "파생 클래스" << std::endl; }
		void what() { std::cout << s << std::endl; }
};

int main() {
	Base p;
	Derived c;
    
	std::cout << "=== 포인터 버전 ===" << std::endl;
    // 포인터 사용
	Base* p_c = &c;
	p_c->what();
    
	return 0;
}

기반 클래스
기반 클래스
파생 클래스
=== 포인터 버전 ===
기반

Derived가 Base를 상속 받았으므로
Base 객체를 가리키는 포인터가 Derived c객체를 가리켜도 무방
단 p는 Base 객체를 가르키는 포인터 이므로 Base class에 있는 것만 사용

※ 코드에서 자주 보인다
사용하는 포인터가 뭘 가르키는지 확인 유의

down casting

기반 클래스에서 파생 클래스로 캐스팅 하는 것

하지만 컴파일 에러 발생
static_cast를 사용하여도 런타임 에러 발생

dynamic_cast

부모 클래스의 포인터에서 자식 클래스의 포인터로 다운 캐스팅 해주는 연산자

불가능

  • 부모클래스의 생성자로 생성되었고 부모 포인터가 가리키고 있는 클래스를
    자식클래스 포인터로

가능

  • 자식클래스의 생성자로 생성되었고 부모클래스 포인터가 가리키고 있는 클래스를
    자식 클래스 포인터로

virtual

가상 함수(virtual function)

  • 런타임시 각 생성된 클래스에 맞는 함수로 실행하게 됨
  • 기반클래스에서 virtual로 정의
  • 파생 클래스의 함수가 기반 클래스의 함수를 오버라이드 하기 위해서는 두 함수의 꼴이 정확히 같아야함
  • 명시적으로 override도 가능 overide 사용
  • 가상 함수를 사용하게 되면 약간의 오버헤드 (overhead) 가 존재

example code


class Base {
	public:
		Base() { std::cout << "기반 클래스" << std::endl; }
		virtual void what() { std::cout << "기반 클래스의 what()" << std::endl; }
};

class Derived : public Base {
	public:
		Derived() : Base() { std::cout << "파생 클래스" << std::endl; }
		void what() { std::cout << "파생 클래스의 what()" << std::endl; }
        
        /*
        void what() override{ std::cout << "파생 클래스의 what()" << std::endl; }
        */
};

int main() {
	Base p;
	Derived c;
    
	Base* p_c = &c;
	Base* p_p = &p;
    
	std::cout << " == 실제 객체는 Base == " << std::endl;
	p_p->what();
    
	std::cout << " == 실제 객체는 Derived == " << std::endl;
	p_c->what();
    
	return 0;
}

기반 클래스
기반 클래스
파생 클래스
== 실제 객체는 Base ==
기반 클래스의 what()
== 실제 객체는 Derived ==
파생 클래스의 what()

virtual 소멸자

상속 시에, 부모 클래스 소멸자를 가상함수로 만들어야 함

아니면
Parent 포인터로 Child 가리켰을 때
Parent *p = new Child();
child 소멸자가 안 불려서 memory leak 발생

pure virtual function

무엇을 하는지 정의되어 있지 않는 함수
파생 클래스에서 반드시 오버라이딩 되어야만 하는 함수
virtual void func() = 0;

example code

class Animal {
	public:
		Animal() {}
		virtual ~Animal() {}
		virtual void speak() = 0;
};

class Dog : public Animal {
	public:
		Dog() : Animal() {}
		void speak() override { std::cout << "왈왈" << std::endl; }
};

class Cat : public Animal {
	public:
		Cat() : Animal() {}
		void speak() override { std::cout << "야옹야옹" << std::endl; }
};

int main() {
	Animal* dog = new Dog();
    Animal* cat = new Cat();
	dog->speak();
	cat->speak();
}

왈왈
야옹야옹

abstract class

순수 가상 함수를 최소 한개 포함하여 반드시 상속 되어야 하는 클래스

multiple inheritance

다중 상속
한 클래스가 다른 여러 개의 클래스들을 상속 받음

  • 상속 순서에 따라 생성자 호출 순서가 달라짐
  • 기반 클래스들에 겹치는 멤버 변수나 함수가 있으면 구분 불가능 > 에러
  • 다이아몬드 상속(diamond inheritance)주의 > virtual 상속을 통해 해결 가능

example code


class A {
	public:
		int a;
		A() { std::cout << "A 생성자 호출" << std::endl; }
};

class B {
	public:
		int b;
		B() { std::cout << "B 생성자 호출" << std::endl; }
};

class C : public A, public B {
	public:
		int c;
		C() : A(), B() { std::cout << "C 생성자 호출" << std::endl; }
};

int main() { C c; }

A 생성자 호출
B 생성자 호출
C 생성자 호출

class 디자인

  • 브릿지 패턴
    N + M 개의 클래스 생성
  • 중접된 일반화
    N ×M 개의 파생 클래스 생성
  • 다중 상속
    N ×M 개의 파생 클래스 생성

reference

포인터 대신 reference 사용가능

example code

class A {
	public:
		virtual void show() { std::cout << "Parent !" << std::endl; }
};

class B : public A {
	public:
		void show() override { std::cout << "Child !" << std::endl; }
};

void test(A& a) { a.show(); }

int main() {
	A a;
	B b;
    
	test(a);
	test(b);
    
	return 0;
}

Parent !
Child !

test함수 래퍼런스로 파라미터를 받아 virtual로 파생클래스의 show함수를 받는다.

profile
soeun choi

0개의 댓글