💻 프로그래밍 언어/C++
C++ 12주차
SA성아
2023. 11. 22. 12:30
상속 (inheritance)
#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";}
};
int main() {
A aa;
return 0;
}
#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 << "c2\n"; }
};
class B : public A { }; //파생클래스, 자식클래스
int main() {
A aa;
aa.b1();
B bb;
//bb.
}
C++에서 상속하는 방법
// 기본 클래스 Animal 정의
class Animal {
public:
void eat() {
cout << "나는 먹는다.\n";
}
};
// 파생 클래스 Dog 정의, Animal 클래스를 상속
class Dog : public Animal {
public:
void bark() {
cout << "멍멍!\n";
}
};
int main() {
Dog myDog; // Dog 객체 생성
myDog.eat(); // 기본 클래스의 메소드 호출
myDog.bark(); // 파생 클래스의 메소드 호출
return 0;
}
프로그래밍 언어의 상속
1. Java
// 기본 클래스 Animal 정의
class Animal {
void eat() {
System.out.println("나는 먹는다");
}
}
// 파생 클래스 Dog 정의, Animal 클래스를 상속
class Dog extends Animal {
void bark() {
System.out.println("멍멍!");
}
}
public class Main {
public static void main(String[] args) {
Dog myDog = new Dog(); // Dog 객체 생성
myDog.eat(); // 기본 클래스의 메소드 호출
myDog.bark(); // 파생 클래스의 메소드 호출
}
}
2. Python
# 기본 클래스 Animal 정의
class Animal:
def eat(self):
print("나는 먹는다")
# 파생 클래스 Dog 정의, Animal 클래스를 상속
class Dog(Animal):
def bark(self):
print("멍멍!")
myDog = Dog() # Dog 객체 생성
myDog.eat() # 기본 클래스의 메소드 호출
myDog.bark() # 파생 클래스의 메소드 호출
3. JavaScript (ES6이상)
// 기본 클래스 Animal 정의
class Animal {
eat() {
console.log("나는 먹는다");
}
}
// 파생 클래스 Dog 정의, Animal 클래스를 상속
class Dog extends Animal {
bark() {
console.log("멍멍!");
}
}
let myDog = new Dog(); // Dog 객체 생성
myDog.eat(); // 기본 클래스의 메소드 호출
myDog.bark(); // 파생 클래스의 메소드 호출
클래스들의 계층구조
상속 과정
기본클래스와 파생클래스 : is-a, is_a, is a 관계
클래스 상속 형식
상속 접근제어 속성에 따른 파생 클래스 멤버의 속성변화
public 상속 접근제어
class Dog : public Animal
▶ 상속을 받게되면 부모의 private를 제외하고 protected와 public이 그대로 넘어온다.
상속
#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 main() {
A aa;
aa.setX(1);
aa.showX();
B bb;
bb.setX(10);
bb.showX();
return 0;
}
▶ bb가 setX와 showX를 사용할 수 있는 이유는 부모로부터 상속받았기 때문
실습 8-1: 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.setX(1); // 오류 ① bb.setX(1);
bb.setY(2); // 오류 ② bb.setY(2);
bb.showX(); // 기본클래스의 멤버접근
bb.showY(); // 파생클래스의 멤버접근
return 0;
}
▶ setX와 showX를 상속받음, x는 private이기 때문에 상속받을 수 없음
실습 8-2: 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() {
showX();
cout << y << endl;
}
};
int main()
{
B bb;
bb.setX(1); // 기본클래스의 멤버접근
bb.setY(2); // 파생클래스의 멤버접근
bb.showX(); // 기본클래스의 멤버접근
bb.showXY(); // 파생클래스의 멤버접근
return 0;
}
private 상속 접근제어
class Dog : private Animal
실습 8-3: 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); // 오류
bb.setY(2); // 파생클래스의 멤버접근
//bb.showX(); // 오류
bb.showY(); // 파생클래스의 멤버접근
return 0;
}
▶ 상속이 되긴 하는데 자식클래스 안에서만 사용할 수 있다.
class B :private A {
int y;
void setX(int i) { x = i; }
void showX() { cout << x << endl; }
public:
void setY(int i) { y = i; }
void showY() { cout << y << endl; }
};
In-class member initializers
#include <iostream>
using std::cout;
using std::endl;
class A
{
int x = 1;// In-class member initializers: 클래스 안에서 멤버값을 바로 초기화하는 방법
public:
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; } // 아래와 똑같은 소스
//A() : x(2) {}
void setX(int i) { x = i; }
int getX() { return x; }
};
int main()
{
A a1; //디폴트 생성자는 사라짐
cout << a1.getX() << endl;
return 0;
}
//2
실습 8-4: 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; }
// 기본 클래스의 public 멤버 접근
void showXY() { showX(); cout << y << endl; }
};
int main()
{
B bb;
bb.setXY(1, 2); // 파생클래스의 멤버접근
bb.showXY(); // 파생클래스의 멤버접근
return 0;
}
▶ private으로 상속받더라도, 기본 클래스의 public 멤버들은 파생 클래스의 멤버함수에 의해서는 접근될 수 있다.
▶ private 상속은 기본클래스의 public 멤버를 파생클래스에서만 접근 가능하게 만든다. 즉, 자식에게만 비밀스럽게 상속한다.
protected 상속 접근제어 속성
class Dog : protected Animal
실습 8-5: protected 멤버변수
#include <iostream>
using std::cout;
using std::endl;
class A
{
protected: //private이라면?
int a, b;
public:
void setAB(int i, int j) { a = i; b = j; }
};
class B :public A
{
int c; // private
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;
}
▶ 기본 클래스 A에서 a, b는 protected이므로 파생 클래스 B에서 접근이 가능하다.
▶ private이면 불가능
protected멤버+public상속(많이 사용하는 스타일)
class A
{
protected: //private이라면?
int a, b;
public:
void setAB(int i, int j) { a = i; b = j; }
};
class B :public A
{
int c; //private
public:
void setC(int n) { c = n; }
void showABC() { cout << a << b << c << endl; }
};
▶ 클래스를 만들 때 클래스 외부에서는 접근하지 못하게 하고 자식클래스에서는 마음대로 접근할 수 있게 하려면 멤버의 속성을 protected로 사용해야 한다.
▶ 상속은 public으로 하자
실습 8-6: 상속에서 생성자와 소멸자
#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;
}
//A의 생성자
//B의 생성자
//B의 소멸자
//A의 소멸자
▶ 부모와 자식에게 생성자와 소멸자가 있을 경우에는, 생성자는 부모가 먼저 소멸자는 자식이 먼저 호출된다.
실습 8-7: 파생 클래스 생성자에서 기본 클래스 생성자에 매개변수전달 형식
#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는 기본클래스 생성자의 매개변수로 전달
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;
}
실습 8-8: 계층적 다중상속에서계층적 매개변수전달 1
#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) {
// 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;
}
실습 8-9: 계층적 다중상속에서 계층적 매개변수 전달 2
#include <iostream>
using std::cout;
using std::endl;
class B { //할아버지
double d;
public:
B(double dd) { d = dd; }
double getD() { return d; }
};
class D1 :public B { //아버지
int i;
public:
D1(double dd, int ii) :B(dd) { i = ii; }
int getI() { return i; }
};
class D2 :public D1 { //자식
char c;
public:
D2(double dd, int ii, char cc) :D1(dd, ii) { c = cc; }
void print() {
cout << "Double : " << getD() << endl;
// B 멤버 호출
cout << "Int : " << getI() << endl;
// D1 멤버 호출
cout << "Char : " << c << endl;
}
};
int main()
{
D2 d2(10.5, 10, 'H');
cout << d2.getD() << ',' << d2.getI() << endl;
// B, D1 멤버 호출
d2.print();
return 0;
}
출처: C++ 프로그래밍