[C++] 상속(Inheritance) - 1 (feat. 개념, 상속 접근 지정자)

2020. 6. 19. 21:46·🖥️ 컴퓨터공학 🖥️/C | C++
반응형

출처 => C++ How to Program (Detitel / Prenticehall) / 현재 그리고 미래지향적인 C++ 프로그래밍(장석우, 임정목 / 비앤씨에듀케이션)

https://lesslate.github.io/cpp/%EC%97%85-%EC%BA%90%EC%8A%A4%ED%8C%85-%EB%8B%A4%EC%9A%B4-%EC%BA%90%EC%8A%A4%ED%8C%85/

 

상속(Inheritance)이란 무엇인가?

▶ 기본 클래스의 속성과 기능을 파생 클래스에 물려주는 것

▶ 기본 클래스는 상속해주는 클래스, 부모클래스라고도 부른다. 파생클래스는 상속받는 클래스이며 자식클래스라고도 부른다. 

▶ 기본클래스에서 파생 클래스로 갈수록 클래스의 개념이 구체화된다. (과일->사과, 자동차->BMW)

 

▶ 상속은 3가지의 장점이 있다.

1. 간결한 클래스 작성

2. 클래스 간의 계층적 분류 및 관리의 용이함

3. 클래스의 재사용과 확장을 통한 소프트웨어 생산성 향상

 

 

 

 

 

상속 관계의 클래스 -Point클래스를 상속받는 ColorPoint클래스 예제

#include<iostream>
#include<string>
using namespace std;

class Point {
	int x, y;
public:
	void set(int x, int y) {
		this->x = x;
		this->y = y;
	}
	void showPoint() {
		cout << "(" << x << "," << y << ")" << endl;
	}
};

class ColorPoint :public Point {
	string color;
public:
	void setColor(string color) {
		this->color = color;
	}
	void showColorPoint();
};

void ColorPoint::showColorPoint() {
	cout << color << ".";
	showPoint();
}

void main() {
	Point p;
	ColorPoint cp;
	cp.set(3, 4);
	cp.setColor("Red");
	cp.showColorPoint();
}

 

소스 코드를 분석해보자.

 

1. Point 클래스

 

 

▶ Point 클래스에서의 멤버 변수는 int 형의 x와 y이다.

▶ set(int x, int y)메소드는 set 메소드 안에서 선언된 x와 y를 Point클래스의 x와 y에 대입을 해주는 역할을 한다.

▶ showPoint( )메소드는 set함수에서 선언한 x와 y를 출력해주는 메소드이다. 클래스 안에서 선언을 하게 되면 엑세스 할 수 없습니다는 오류가 발생하기 때문에 선언만 클래스 안에서 해주고 세부 내용은 밖에서 정의해야 한다. 

 

2. ColorPoint 클래스

 

 

▶ ColorPoint 클래스는  public의 형태로 Point 클래스를 상속받는다.

▶ setColor(string color) 메소드는 setColor(string color)메소드에서 선언된 color을 ColorPoint클래스의 color에 대입해준다.

▶ showColorPoint( )메소드는 setColor메소드에서 대입한 color의 값을 출력해주는 역할을 한다.

▶ showPoint( )는 Point 클래스의 메소드. 상속을 받았기 때문에 사용이 가능하다. (단, ColorPoint의 메소드는 Point클래스에서는 사용이 불가하다!!!)

 

 

 

상속과 객체 포인터

1. 업 캐스팅(up-casting)

▶ 파생 클래스의 객체를 기본 클래스의 포인터로 가리키는 것을 말한다.

▶ 파생클래스의 객체를 기본 클래스의 객체처럼 다룰 수 있게 한다.

#include<iostream>
#include<string>
using namespace std;

class Circle {
public:
	int radius;
public:
	void setRadius(int r) {
		radius = r;
	}
	void showRadius() {
		cout << "반지름" << radius << endl;
	}
};

class Pizza :public Circle {
public:
	double getArea();
};
double Pizza::getArea() {
	return radius * radius * 3.14;
}

void main() {
	Circle c;
	c.setRadius(5);
	c.showRadius();
	//반지름 알려주는 과정
	
	Pizza hp;
	Pizza* cDer = &hp;
	Circle* cBase = cDer;//업캐스팅
	
	cBase->setRadius(100);
	cout < cDer->getArea() << endl;
	cBase->getArea();
}

▶ 이는 오류가 발생한다.!!!

Pizza hp;
Pizza* cDer = &hp;
Circle* cBase = cDer;//업캐스팅

▶ cBase는 Circle 클래스의 포인터이므로 cBase 포인터로는 Circle 클래스 멤버만 접근할 수 있다. 

▶ 그러므로 getArea()함수는 Circle 클래스의 멤버가 아니라 Pizza 클래스에서 선언된 멤버이므로 오류가 발생한다.

 

2. 다운 캐스팅(Down Casting)

▶ 기본 클래스 포인터가 가리키는 객체를 파생 클래스의 포인터로 가리키는 것을 다운 캐스팅이라고 한다.

▶ 자식 형식에서 부모 형식을 사용하는 것이며 업 캐스팅에서 다시 원래의 형으로 되돌려주는 작업이다.

 

#include<iostream>
#include<string>
using namespace std;

class Circle {
public:
	int radius;
public:
	void setRadius(int r) {
		radius = r;
	}
	void showRadius() {
		cout << "반지름" << radius << endl;
	}
};

class Pizza :public Circle {
public:
	double getArea();
};
double Pizza:: getArea() {
	return radius * radius * 3.14;
}

void main() {
	Circle c;
	c.setRadius(5);//반지름 입력
	c.showRadius();//반지름 출력

	Pizza hp;
	hp.setRadius(10);
	cout << "햄 피자 면적:" << hp.getArea() << endl;

	Pizza cheesepizza;
	Pizza* cDer = &cheesepizza; //치즈피자의 주소값을 cDer에 입력
	Circle* cBase = cDer;//업 캐스팅

	cBase->setRadius(100);
	cBase->showRadius();

	cDer = (Pizza*)cBase;
	cDer->setRadius(1);
	cDer->showRadius();
	cout << "치즈 피자면적:" << cDer->getArea() << endl;
}

 

 

 

상속과 생성자

▶ 파생 클래스의 객체는 기본 클래스의 생성자를 무조건적으로 호출한다. (소멸자도 역시 호출)

 

▶ main 메소드에서는 B클래스의 객체인 b(5)만 선언했을 뿐인데 생성자 A( )가 호출되었음을 알 수 있다.

▶ 파생 클래스의 생성자가 기본 클래스의 기본 생성자를 선택하는 방법은 크게 두 가지가 있다.

 

1. 묵시적으로 기본 클래스의 기본 생성자를 선택하는 경우

#include<iostream>
using namespace std;

class A {
public:
	A() {
		cout << "생성자 A" << endl;
	}
	A(int x) {
		cout << "매개변수생성자 A" << endl;
	}
};

class B :public A {
public:
	B() {
		cout << "생성자 B" << endl;
	}
	B(int x) {
		cout << "매개변수생성자 B" << endl;
	}
};

void main() {
	B b(5);
}

 

 

2. 기본 클래스의 생성자를 명시적으로 선택하는 경우

#include<iostream>
using namespace std;

class A {
public:
	A() {
		cout << "생성자 A" << endl;
	}
	A(int x) {
		cout << "매개변수생성자 A" << endl;
	}
};

class B : public A {
public:
	B() {
		cout << "생성자 B" << endl;
	}
	B(int x) :A(x+3){
		cout << "매개변수생성자 B" << endl;
	}
};

void main() {
	B b(5);
}

 

 

 

상속 지정 (public, private, protected)

▶ 상속을 선언할 때는 public, private, protected 이 세 가지 방법으로 지정할 수 있다. 지금까지 위에 있는 예시들은 모두 public형태로 상속을 한 것들이다. 

▶ 어떤 식으로 상속하느냐에 따라 멤버들의 범위도 바뀐다.

▶ public -> 기본 클래스의 public, private, protected 멤버 속성을 그대로 계승한다.

▶ protected -> 기본 클래스의 protected, public 멤버를 protected로 계승한다.

▶ private -> 기본 클래스의 protected, public 멤버를 private으로 계승한다.

 

 

1. public으로 지정하여 상속하는 예제

#include<iostream>
using namespace std;

class Base {
public:
	int a = 3;
	void publicOfBase() {
		cout << "Base의 public 메소드입니다" << endl;
	}
protected:
	int b = 4;
	void protectedOfBase() {
		cout << "Base의 public 메소드입니다" << endl;
	}
private:
	int c = 5;
	void priavateOfBase() {
		cout << "Base의 public 메소드입니다" << endl;
	}
};

class Derived :public Base {

public:
	int d = 13;
	void publicOfDerived() {
		cout << "Derived의 public 메소드입니다" << endl;
	}
protected:
	int e = 14;
	void protectedOfDerived() {
		cout << "Derived의 public 메소드입니다" << endl;
	}
private:
	int f = 15;
	void priavateOfDerived() {
		cout << "Derived의 public 메소드입니다" << endl;
	}



};

void main() {
	Derived d;

	cout << "Base의 public 변수는 " << d.a << endl;
	cout << "Base의 protected 변수는" << d.b << endl;//오류 발생
	cout << "Base의 private 변수는 " << d.c << endl;//오류 발생

	cout << "Derived의 public 변수는 " << d.d << endl;
	cout << "Derived의 protected 변수는" << d.e << endl;//오류 발생
	cout << "Derived의 private 변수는 " << d.f << endl;//오류 발생

	d.publicOfBase();
	d.protectedOfBase();//오류 발생
	d.privateOfBase();//오류 발생
	
	d.publicOfDerived();
	d.protectedOfDerived();//오류 발생
	d.privateOfDerived();//오류 발생
}

<설명>

▶ 위의 소스코드는 public 형태로 기본 클래스를 상속받은 경우이다. 

▶ 먼저 main() 함수를 보자 

void main() {
	Derived d;

	cout << "Base의 public 변수는 " << d.a << endl;
	cout << "Base의 protected 변수는" << d.b << endl;//오류 발생
	cout << "Base의 private 변수는 " << d.c << endl;//오류 발생

	cout << "Derived의 public 변수는 " << d.d << endl;
	cout << "Derived의 protected 변수는" << d.e << endl;//오류 발생
	cout << "Derived의 private 변수는 " << d.f << endl;//오류 발생

	d.publicOfBase();
	d.protectedOfBase();//오류 발생
	d.privateOfBase();//오류 발생
	
	d.publicOfDerived();
	d.protectedOfDerived();//오류 발생
	d.privateOfDerived();//오류 발생
}

▶ 주석처리된 부분은 오류가 난 부분이다. protected 형태는 지정된 클래스와 상속받은 클래스에서만 사용가능하고, private 형태는 지정된 클래스에서만 사용가능하다. 따라서 main( ) 메소드에서는 외부함수이므로 사용이 불가능하여 public 형태만 출력이 가능한 것이다. 

 

 

2. protected으로 지정하여 상속받는 예제

#include<iostream>
using namespace std;

class Base {
public:
	int a = 3;
	void publicOfBase() {
		cout << "Base의 public 메소드입니다" << endl;
	}
protected:
	int b = 4;
	void protectedOfBase() {
		cout << "Base의 public 메소드입니다" << endl;
	}
private:
	int c = 5;
	void priavateOfBase() {
		cout << "Base의 public 메소드입니다" << endl;
	}
};

class Derived :protected Base {

public:
	int d = 13;
	void publicOfDerived() {
		cout << "Derived의 public 메소드입니다" << endl;
	}
protected:
	int e = 14;
	void protectedOfDerived() {
		cout << "Derived의 public 메소드입니다" << endl;
	}
private:
	int f = 15;
	void priavateOfDerived() {
		cout << "Derived의 public 메소드입니다" << endl;
	}



};

void main() {
	Derived d;

	cout << "Base의 public 변수는 " << d.a << endl;//오류 발생
	cout << "Base의 protected 변수는" << d.b << endl;//오류 발생
	cout << "Base의 private 변수는 " << d.c << endl;//오류 발생

	cout << "Derived의 public 변수는 " << d.d << endl;
	cout << "Derived의 protected 변수는" << d.e << endl;//오류 발생
	cout << "Derived의 private 변수는 " << d.f << endl;//오류 발생

	d.publicOfBase();//오류 발생
	d.protectedOfBase();//오류 발생
	d.privateOfBase();//오류 발생
	
	d.publicOfDerived();
	d.protectedOfDerived();//오류 발생
	d.privateOfDerived();//오류 발생
}

 

▶ main 함수를 보자. 변화가 생긴듯 하다. 

void main() {
	Derived d;

	cout << "Base의 public 변수는 " << d.a << endl;//오류 발생
	cout << "Base의 protected 변수는" << d.b << endl;//오류 발생
	cout << "Base의 private 변수는 " << d.c << endl;//오류 발생

	cout << "Derived의 public 변수는 " << d.d << endl;
	cout << "Derived의 protected 변수는" << d.e << endl;//오류 발생
	cout << "Derived의 private 변수는 " << d.f << endl;//오류 발생

	d.publicOfBase();//오류 발생
	d.protectedOfBase();//오류 발생
	d.privateOfBase();//오류 발생
	
	d.publicOfDerived();
	d.protectedOfDerived();//오류 발생
	d.privateOfDerived();//오류 발생
}

▶ d.publicOfBase()메소드와 d.a에 오류가 발생하였다. 

▶ 지금 위의 예제는 Base클래스를 protected의 형태로 상속받는 상황이다. protected는 지정된 클래스와 상속받은 클래스에서만 사용이 가능하다. 그러기에 main()함수는 외부함수이므로 Base 클래스에 접근을 할 수가 없다. 따라서 Base의 클래스 안에 있는 변수 a와 publicOfBase는 출력될 수 없다. 

 

3. private로 지정하여 상속받는 예제

#include<iostream>
using namespace std;

class Base {
public:
	int a = 3;
	void publicOfBase() {
		cout << "Base의 public 메소드입니다" << endl;
	}
protected:
	int b = 4;
	void protectedOfBase() {
		cout << "Base의 public 메소드입니다" << endl;
	}
private:
	int c = 5;
	void priavateOfBase() {
		cout << "Base의 public 메소드입니다" << endl;
	}
};

class Derived :private Base {

public:
	int d = 13;
	void publicOfDerived() {
		cout << "Derived의 public 메소드입니다" << endl;
	}
protected:
	int e = 14;
	void protectedOfDerived() {
		cout << "Derived의 public 메소드입니다" << endl;
	}
private:
	int f = 15;
	void priavateOfDerived() {
		cout << "Derived의 public 메소드입니다" << endl;
	}



};

void main() {
	Derived d;

	cout << "Base의 public 변수는 " << d.a << endl;//오류 발생
	cout << "Base의 protected 변수는" << d.b << endl;//오류 발생
	cout << "Base의 private 변수는 " << d.c << endl;//오류 발생

	cout << "Derived의 public 변수는 " << d.d << endl;
	cout << "Derived의 protected 변수는" << d.e << endl;//오류 발생
	cout << "Derived의 private 변수는 " << d.f << endl;//오류 발생

	d.publicOfBase();//오류 발생
	d.protectedOfBase();//오류 발생
	d.privateOfBase();//오류 발생
	
	d.publicOfDerived();
	d.protectedOfDerived();//오류 발생
	d.privateOfDerived();//오류 발생
}
728x90
반응형

'🖥️ 컴퓨터공학 🖥️ > C | C++' 카테고리의 다른 글

[C++] 제네릭 함수 (feat. template)  (0) 2020.06.21
[C++] 상속(Inheritance) - 2 (feat. 가상 함수와 추상클래스)  (0) 2020.06.20
[C++] 연산자 중복 (feat. 프랜드 함수)  (0) 2020.06.19
[C++] 프랜드 함수  (0) 2020.06.19
[C++] 생성자와 소멸자  (0) 2020.06.18
'🖥️ 컴퓨터공학 🖥️/C | C++' 카테고리의 다른 글
  • [C++] 제네릭 함수 (feat. template)
  • [C++] 상속(Inheritance) - 2 (feat. 가상 함수와 추상클래스)
  • [C++] 연산자 중복 (feat. 프랜드 함수)
  • [C++] 프랜드 함수
공대생 배기웅
공대생 배기웅
군노답 미필 공대생 배기웅의 대학생활을 갈아 넣은 블로그
    반응형
  • 공대생 배기웅
    글쓰는공대생의 IT블로그
    공대생 배기웅
  • 전체
    오늘
    어제
    • 분류 전체보기 (166)
      • 🖊️ 공대생 글쓰기 🖊️ (17)
        • 공대생 회고록 (4)
        • 공대생의 끄적끄적 (4)
        • 슬기로운 공대생활 (9)
        • 사회초년생의 업무일기 (0)
      • 📈 산업공학 📈 (14)
        • 금융, 파생상품 (13)
        • 통계 (0)
        • 재무회계 (1)
      • 🖥️ 컴퓨터공학 🖥️ (92)
        • 머신러닝, 딥러닝 (12)
        • 텐서플로우, 케라스 (1)
        • 알고리즘 (24)
        • 웹 (5)
        • Python (3)
        • C | C++ (23)
        • Java (15)
        • 코드 에러 모음집 (9)
      • 😙 취미, 교양 😙 (2)
        • 영어공부 (1)
        • 일본어회화 공부 (1)
      • 🔍 정보 공유 🔍 (38)
        • 대학생 외부활동 정보 (2)
        • 개발자관련 정보 (3)
        • 대입 논술 입시자료 정보 (22)
        • 프로그램 세팅 (11)
  • 블로그 메뉴

    • 홈
    • 방명록
  • 링크

  • 공지사항

    • [공지] 글쓰는 공대생입니다 😃
  • 인기 글

  • 태그

    예외
    경제성공학
    무작위 변수
    Operator
    객체지향
    프랜드함수
    Java
    equals프레임워크
    자바
    백준
    프로그래머스
    조작자
    이클립스
    OOP
    재귀함수
    C++
    스캐너
    acmicpc
    데이터베이스
    알고리즘
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
공대생 배기웅
[C++] 상속(Inheritance) - 1 (feat. 개념, 상속 접근 지정자)
상단으로

티스토리툴바