일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- std::ostream
- c++ multi chatting room
- pointer to member data
- std::endl
- vector capacity
- virtual function
- dynamic_cast
- delete function
- operator overloading
- virtual inheritance
- virtual function table
- C++
- this call
- suffix return type
- std::vector
- discord bot
- c++ basic practice
- std::cout
- virtual destructor
- increment operator
- return by reference
- vector size
- placement new
- constructor
- new&delete
- member function pointer
- conversion constructor
- 더 지니어스 양면포커
- base from member
- diamond inheritance
- Today
- Total
I'm FanJae.
[C++] Inheritance(상속) 본문
※ 본 포스트는 코드누리 C++ Basic 강의 내용을 보고 정리한 포스트입니다.
1. Inhertance
#include <string>
class Student
{
std::string name;
int age;
int id;
};
class Professor
{
std::string name;
int age;
int major;
};
int main()
{
Student s;
Professor p;
}
- 학사 관리 프로그램을 만들고 있는 상태에서, Student, Professor 등 필요한 클래스를 설계중이다.
- 여기서 Student, Professor 등이 가지는 공통된 속성(name,age)이 있다.
- 이를 매번 적어주기 보단 공통된 것으로 묶어지면 훨씬 더 관리가 용이하다.
class Person
{
std::string name;
int age;
};
class Student : public Person
{
std::string name;
int age;
int id;
};
class Professor : public Person
{
std::string name;
int age;
int major;
};
int main()
{
Student s;
Professor p;
}
- 이와 같이 기반 클래스인 Person으로 부터, name과 id를 물려 받는 것을 확인이 가능하다.
- 이와 같이 타입을 확장해서 새로운 타입을 설계하는 문법이다.
1-1. 장점
- 코드의 중복을 줄일 수 있다.
- upcasting, 가상함수, 다형성, 인터페이스 등 다양한 개념을 활용해서 객체지향 설계 기술을 사용할 수 있다.
※ 상속은 대부분의 객체지향 언어가 지원한다.
C++ | class Student : public Person |
C# | class Student : Person |
Java | class Student extends Person |
Python | class Student (Person) |
1-2. Base Class & Derived Class
- 상속을 표현하는 그림에 대해서 이해하는 것이 매우 중요하다.
- 이때, Person과 같은 Class를 특정 Class에게 상속의 대상으로 사용되는 Base Class(기반 클래스)라고 한다.
- 그리고, 그 아래에 Student 같이 상속을 받아오는 Class를 Derived Class(파생 클래스)라고 한다.
1-3. C++ 언어가 지원하는 3개의 접근 지원자
private | 자신의 멤버 함수와 friend 함수에서 접근 가능 파생 클래스 멤버 함수 에서는 접근 안됨 |
protected | 자신의 멤버 함수와 friend 함수 파생클래스 멤버 함수와 friend 함수에서 접근 가능 멤버가 아닌 함수에서는 접근 안됨. |
public | 모든 함수에서 접근 가능 |
class Base
{
private: int a;
protected: int b;
public: int c;
};
class Derived : public Base
{
public:
void df()
{
a = 10; // error
b = 10; // ok
c = 20; // ok
}
};
int main()
{
Derived de;
de.a = 10; // error
de.b = 10; // error
de.c = 10; // ok
}
- Protected인 경우, public 처럼 바로 접근을 하는 것은 불가능하다 멤버 함수를 이용해서 접근을 하는것은 가능하다.
2. Constructor in Inhertance
#include <iostream>
using namespace std;
class Base
{
int data;
public:
Base() { cout << "Base()" << endl; }
Base(int a) { cout << "Base(int)" << endl; }
~Base() { cout << "~Base()" << endl; }
};
class Derived : public Base
{
public:
Derived() { cout << "Derived()" << endl; }
Derived(int a) : Base(a) { cout << "Derived(int)" << endl; }
~Derived() { cout << "~Derived()" << endl; }
};
int main()
{
Derived d1();
Derived d2(5);
}
- 위 예제는 상속에서의 생성자 호출의 원리이다. 상당히 중요하므로, 잘 알아놔야될 것 같다.
- 위와 같은 코드가 있다고 하면, Derived 타입의 객체 d1을 생성하면, Base의 생성자도 호출된다.
- 호출이 될때의 순서는 기반 클래스인 Base가 먼저 생성되고, 그 뒤에 파생 클래스인 Derived가 생성되는 순서이다.
- Derived d2(5)와 같이 인자를 넣어 부를 경우에도 Base 생성자는 항상 인자가 없는 디폴트 생성자가 생성된다.
- Derived() 생성자를 호출하면, 이들이 우선 기반 클래스에 생성자를 부르도록 처리해준다.
- Derived()의 소멸자를 호출할 때도, 소멸자 마지막 부분에 기반 클래스의 소멸자를 호출하는 코드를 생성해 정리해준다.
- 이와 같이, 생성자를 부를때는 먼저 기반 클래스의 생성자 호출이 일어난 이후, 파생 클래스를 생성자를 호출한다.
- 반면, 소멸자는 파생 클래스에서 여러 작업이 진행된 이후, 기반 클래스의 소멸자가 마지막에 호출한다.
※ 기본적으로 컴파일러가 생성해주는 코드는 항상 기반 클래스의 디폴트 생성자를 호출한다.
※ 다른 버전의 생성자를 호출하려면 기반 클래스 다른 버전의 생성자를 호출하는 코드를 직접 작성해야 한다.
2-1. 기반 클래스(Base)에 디폴트 생성자가 없는 경우
- 파생 클래스의 생성자에서 기반 클래스(Base) 생성자를 호출하는 코드를 반드시 작성해야한다.
#include <iostream>
using namespace std;
class Base
{
int data;
public:
// Base() : data(0) { } 기본 생성자 없음
Base(int a) : data(a) { }
~Base() { }
};
class Derived : public Base
{
int data2;
public:
Derived() : Base(0), data2(0) { }
Derived(int a) : Base(a), data2(a) { }
~Derived() { }
};
int main()
{
// Derived d;
Derived d(5);
}
- 위처럼 기반 클래스의 기본 생성자가 없으면, 직접 만들어서 추가해야한다.
Dervied() : data2(0), Base(0) {}
- 기반 클래스 생성자 호출을 멤버 초기화 리스트 가장 앞쪽에 놓는것이 관례이다.
- 뒤에 놓아도 오류가 발생하지 않지만, Base(0)이 먼저 실행되므로, 가독성을 위해 기반 클래스 생성자를 앞에 두자.
2-2. 기본 생성자가 없는 경우도 많다.
#include <string>
class Person
{
std::string name;
int age;
public:
Person(const std::string& n, int a) : name(n), age(a)
{
}
};
class Student : public Person
{
int id;
public:
Student(const std::string& n, int a, int id) : Person(n, a), id(id) {}
};
int main()
{
Student s1;
Student s2("kim", 20, 100);
}
- Default 생성자가 없는 상황일때 더 코드가 안전한 경우도 존재한다.
- 이럴 경우, 파생 클래스의 생성자에서 기반 클래스 생성자로 인자를 보내줄 수 있도록 처리해준다.
Student(const std::string& n, int a, int id) : Person(n, a), id(id) {}
- 이와 같이 보내주는 방법을 상속을 할 때 많이 사용한다.
'C++ > Basic' 카테고리의 다른 글
[C++] Abstract class, Interface (0) | 2024.08.21 |
---|---|
[C++] Upcasting, Virtual Function (0) | 2024.08.21 |
[C++] Copy Constructor (0) | 2024.08.19 |
[C++] this, Reference return (0) | 2024.08.18 |
[c++] const member function, mutable (0) | 2024.08.17 |