상속성(Inheritance) :
C에서는 새로운 내용을 추가할 수 없다, (printf()함수를 수정하고싶다 -> X)
하지만 객체지향언어인 C++에서는 상속성을 제공하여 이미 존재하는 클래스로부터 기본적인 특성을 물려받아 그대로 사용하고 새로운 특성만 추가로 정의할 수 있다,
- 장점 : 기존의 클래스를 그대로 사용할 수 있는 장점이 있고 새로운 클래스를 보다 쉽게 만들 수 있다.
class B : public A // class B : public 부모
상속 : 코드 재사용
#include <iostream>
using std::cout;
class A // 기본 클래스, 부모 클래스
{
private:
void a1() {cout << "a1\n"; }
void a2() {cout << "a2\n"; }
public:
void b1() {cout << "b1\n"; }
void b2() {cout << "b2\n"; }
void b3() {cout << "b3\n"; }
void b4() {cout << "b4\n"; }
protected: //자식에게만
void c1() {cout << "c1\n"; }
void c2() {cout << "c1\n"; }
};
class B { };
//class B : public A { //파생클래스, 자식클래스
};
int main()
{
A aa;
aa.b1();
B bb;
bb.
}
-> A 클래스로부터 public으로 상속받은 B 클래스
여러 프로그램 언어의 상속 예제
1. python
class Animal: # 부모 클래스
def speak(self):
pass
class Dog(Animal): # 자식 클래스
def speak(self):
return "멍멍"
class Cat(Animal): # 자식 클래스
def speak(self):
return "야옹"
2. JAVA
class Animal { // 부모 클래스
void speak() {
}
}
class Dog extends Animal { // 자식 클래스
void speak() {
System.out.println("멍멍");
}
}
class Cat extends Animal { // 자식 클래스
void speak() {
System.out.println("야옹");
}
}
3. kotlin
클래스 다이어그램을 그릴 때는 파생에서 기본으로 화살표가 향하게. 빈 화살표로 그림.
부모 (superclass), 기본(Base) 클래스
자식 (subclass), 파생(Derived) 클래스
- is -a 관계
- class 파생클래스명 : 상속접근제어 기본클래스명 { };
- class Dog : public Animal { };
- Animal 클래스로부터 public으로 상속받은 Dog클래스
부모의 private은 상속불가.
protected은 protected로, public은 public으로 바뀌어서 가져간다.
- public 상속 접근인 경우에는 기본 클래스의 모든 public, protected멤버들은 파생 클래스의 public, protected 멤버가 된다.
- Animal이라는 부모가 있다고할 때 Dog가 상속을 받는 경우
- 상속 예제
#include <iostream>
using std::cout;
using std::endl;
class A // 기본 클래스
{
int x; //아무것도 없으면 private
public:
void setX(int i) {x =i;}
void showX() { cout << x << endl; }
};
class B : public A //파생 클래스
{
//아무 것도 없어요. 그러나!
};
int main() {
A aa;
aa.setX(1);
aa.showX();
B bb;
bb.setX(10);
bb.showX();
return 0;
}
int x를 제외한 public을 상속받음
- public 상속 접근제어 예제 1
#include <iostream>
using std::cout;
using std::endl;
class A // 기본 클래스
{
int x;
public:
void setX(int i) { x = i; }
void showX() { cout << x << endl; }
};
class B :public A //파생 클래스
{
int y;
public:
void setY(int i) { y = i; }
void showY() { cout << y << endl; }
};
int main()
{
B bb; // 파생클래스의 객체
bb.x = 1; // 오류-부모의 private이기 때문에. ① bb.setX(1);
bb.y = 2; // 오류-y가 private이기 때문에. ② bb.setY(2);
bb.showX(); // 기본클래스의 멤버접근
bb.showY(); // 파생클래스의 멤버접근
return 0;
}
- public 상속 접근제어 예제 2
#include <iostream>
using std::cout;
using std::endl;
class A
{
int x;
public:
void setX(int i) { x = i; }
void showX() { cout << x << endl; }
};
class B :public A
{
int y;
public:
void setY(int i) { y = i; }
void showXY() { cout << x << y << endl; } //오류 - x가 부모의 private이기때문에 상속되지 않아 사용할 수 없음.
//void showXY() { showX(); cout << y << endl; } //x를 출력하는 showX를 사용하면 됨.
};
int main()
{
B bb;
bb.setX(1); // 기본클래스의 멤버접근
bb.setY(2); // 파생클래스의 멤버접근
bb.showX(); // 기본클래스의 멤버접근
bb.showXY(); // 파생클래스의 멤버접근
return 0;
}
- privat 상속 : 부모의 private는 상속되지 않고 protected와 public은 private로 바뀌어서 상속된다.
- 자식만 접근 가능 (파생클래스의 멤버함수에 의해서만 접근 가능)
- private 상속 접근제어 예제 1
#include <iostream>
using std::cout;
using std::endl;
class A
{
int x; //int x=10; //가능?
public:
void setX(int i) { x = i; }
void showX() { cout << x << endl; }
};
class B :private A //비공개적으로 상속
{
int y;
public:
void setY(int i) { y = i; }
void showY() { cout << y << endl; }
};
int main()
{
A aa;
B bb;
aa.setX(1);
aa.showX();
bb.setX(1); // 오류 - 상속을 private로 받았기 때문에 setX를 사용 못함.
bb.setY(2); // 파생클래스의 멤버접근
bb.showX(); // 오류 - 상속을 private로 받았기 때문에
bb.showY(); // 파생클래스의 멤버접근
return 0;
}
- In-class member initializers
#include <iostream>
using std::cout;
using std::endl;
class A
{
int x = 1;// In-class member initializers - 클래스 안에서 멤버값을 초기화 해주는 방법
public:
//A() {} 디폴트 생성자 눈에 안보임
void setX(int i) { x = i; }
int getX() { return x; }
};
int main()
{
A a1; //디폴트 생성자 호출, 눈에 안보이는 A(){}
cout << a1.getX() << endl;
return 0;
}
//1
#include <iostream>
using std::cout;
using std::endl;
class A
{
int x = 1;
public:
A() { x = 2; } //디폴트 생성자. 생성자는 예외로 void 안씀
// A() : x(2) {} //8번째줄과 같은 소스임.
void setX(int i) { x = i; }
int getX() { return x; }
};
int main()
{
A a1; //디폴트 생성자는 사라짐
cout << a1.getX() << endl;
return 0;
}
//2
- private 상속 제어접근 용도
#include <iostream>
using std::cout;
using std::endl;
class A
{
int x;
public:
void setX(int i) { x = i; }
void showX() { cout << x << endl; }
};
class B :private A //비공개적으로 상속받는다.
{
int y;
public:
void setXY(int i, int j) { setX(i); y = j; } //setx = x. 자식은 접근 가능하니까 setX사용 가능한거임.
// 기본 클래스의 public 멤버 접근
void showXY() { showX(); cout << y << endl; }
};
int main()
{
B bb;
bb.setXY(1, 2); // 파생클래스의 멤버접근
bb.showXY(); // 파생클래스의 멤버접근
return 0;
}
- protected 상속 접근제어 : 넘어갈 때 모두 protected로 바뀌어서 넘어간다.
- 자식 class에 protected부분이 없다면 private부분으로 상속된다.
private과 protected의 공통점은 외부에서 접근이 불가능 하다는 것.
차이점은 부모가 private는 자식에게 상속 안되는데 protcted는 자식에게 상속 된다는 점.
- protected 멤버 변수
#include <iostream>
using std::cout;
using std::endl;
class A
{
protected: //private이라면? - 자식인 class B에서 int a, b를 접근하지 못해 오류 발생
int a, b;
public:
void setAB(int i, int j) { a = i; b = j; }
};
class B :public A
{
int c; // private
//ptorected
// int a, b;
public:
void setC(int n) { c = n; }
void showABC() { cout << a << b << c << endl; }
//기본 클래스의 protected 멤버들은
//파생 클래스의 멤버에 의해 접근될 수 있다.
};
int main()
{
A aa;
B bb;
aa.a; //외부에서는 접근불가
bb.b; //외부에서는 접근불가
bb.setAB(1, 2);
bb.setC(3);
bb.showABC();
return 0;
}
- 외부에서는 접근을 막고 자식클래스에서는 접근 가능하게 하려면 멤버의 속성을 protected로 사용
- 상속은 public으로!
- 상속에서 생성자와 소멸자
#include <iostream>
using std::cout;
class A
{
public:
A() { cout << "A의 생성자\n"; }
~A() { cout << "A의 소멸자\n"; }
};
class B :public A
{
public:
B() { cout << "B의 생성자\n"; }
~B() { cout << "B의 소멸자\n"; }
};
int main()
{
B ob;
return 0;
}
//실제 B 클래스의 구성
class B :public A
{
public:
A() { cout << "A의 생성자 "; }
~A() { cout << "A의 소멸자 "; }
B() { cout << "B의 생성자 "; }
~B() { cout << "B의 소멸자 "; }
};
// 상속을 받으면 부모의 생성자가 먼저 호출됨. 소멸자는 역순으로 실행됨.
생성자는 부모가 먼저. 소멸자는 역순.
- 매개변수가 있는 생성자를 갖는 클래스의 상속
#include <iostream>
using std::cout;
using std::endl;
class A {
int a;
public:
A(int i) {
cout << "A의 생성자\n";
a = i;
}
~A() { cout << "A의 소멸자\n"; }
void showA() { cout << a << '\n'; }
};
class B :public A {
int b;
public:
B(int i, int j) :A(i) {// i는 기본클래스 생성자의 매개변수로 전달. 자식쪽에서 부모쪽(int i)으로 전달
cout << "B의 생성자\n";
b = j;
}
~B() { cout << "B의 소멸자\n"; }
void showB() { cout << b << endl; }
};
int main()
{
B bb(10, 20);
bb.showA();
bb.showB();
return 0;
}
- 계층적 다중 상속
#include <iostream>
using std::cout;
using std::endl;
class A //할아버지
{
int a;
public:
A(int i) { a = i; }
int getA() { return a; }
};
class B :public A //아버지
{
int b;
public:
B(int i, int j) :A(i) { //A의 자식이라서 i뿐만아니라 j도 만들어서 A(i)는 class A에 생성자 매개변수로 전달
// i는 기본 클래스 A의
//생성자 매개변수로 전달됨
b = j;
}
int getB() { return b; }
};
class C :public B //자식
{
int c;
public:
C(int i, int j, int k) :B(i, j) {
// i, j는 클래스 B의 생성자 매개변수로 전달됨
c = k;
}
void show() {
cout << getA() << ' ' << getB() << ' ' << c << endl;
}
};
int main()
{
C cc(10, 20, 30);
cc.show();
cout << cc.getA() << ' ' << cc.getB() << endl;
return 0;
}
'C++' 카테고리의 다른 글
2. C문법 (자료형, 전처리기, 식별자, 리터럴, 변수, 연산자) (0) | 2024.09.13 |
---|---|
1. C++ 개요 (6) | 2024.09.03 |
9-2 디폴트 인자(매개변수) (0) | 2023.11.15 |
9-1 함수중첩 (0) | 2023.11.15 |
6-1 클래스 (0) | 2023.10.18 |