씹어먹는 C++
7장 클래스의 상속 298p - 339p
is - a / has - a
모든 상속 관계
뒤 바꾸면 성립 안됨
기반 클래스의 모든 기능을 파생 클래스가 포함
파생 is a 기반
파생 클래스에서 기반 클래스로 캐스팅 하는 것
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에 있는 것만 사용
※ 코드에서 자주 보인다
사용하는 포인터가 뭘 가르키는지 확인 유의
기반 클래스에서 파생 클래스로 캐스팅 하는 것
하지만 컴파일 에러 발생
static_cast를 사용하여도 런타임 에러 발생
부모 클래스의 포인터에서 자식 클래스의 포인터로 다운 캐스팅 해주는 연산자
불가능
가능
가상 함수(virtual function)
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()
상속 시에, 부모 클래스 소멸자를 가상함수로 만들어야 함
아니면
Parent 포인터로 Child 가리켰을 때
Parent *p = new Child();
child 소멸자가 안 불려서 memory leak 발생
무엇을 하는지 정의되어 있지 않는 함수
파생 클래스에서 반드시 오버라이딩 되어야만 하는 함수
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();
}
왈왈
야옹야옹
순수 가상 함수를 최소 한개 포함하여 반드시 상속 되어야 하는 클래스
다중 상속
한 클래스가 다른 여러 개의 클래스들을 상속 받음
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 생성자 호출
포인터 대신 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함수를 받는다.