5.3 파생 시에 액세스 지정
지금까지 파생을 표현할 때 기반 클래스의 접근 수준을 변경없이 파생하였습니다. 이 외에도 protected 상속과 private 상속이 있는데 어떠한 차이가 있고 어떠한 경우에 사용될 수 있는지 알아봅시다.
파생할 때 기반 클래스 명 앞에 붙는 접근 지정자는 기반 클래스의 멤버들의 가시성이 허용되는 수준 중에 가장 넓은 가시성을 갖을 수 있는 수준을 지정하는 것입니다. 만약, protected 상속을 하였을 경우 기반 클래스에 public인 멤버는 가시성이 protected보다 넓을 수 없기 때문에 protected로 강화됩니다. 주의할 것은 기반 클래스의 private 멤버는 어떠한 상속이든지에 상관없이 파생된 스코프에서는 가시성이 없습니다.
|
public 상속 |
protected 상속 |
private 상속 |
public |
public |
protected |
private |
protected |
protected |
protected |
private |
private |
가시성 없음 |
가시성 없음 |
가시성 없음 |
public 상속은 기반 클래스에서 지정한 접근 수준을 파생 클래스에서도 계속 유지됩니다. 물론, private으로 가시성이 지정된 멤버는 파생된 곳에서 보이지 않기 때문에 논외입니다. 하지만 protected 상속은 기반 클래스에 있는 모든 멤버를 파생 관계에 있는 곳이 아닌 곳에서는 가시성이 없게 됩니다. private 상속은 기반 클래스에 있는 모든 멤버를 파생 클래스 자신은 보이지만 자신에서 다시 파생된 모든 스코프까지도 가시성이 없게 됩니다.
protected 상속이나 private 상속은 기존에 제공되던 라이브러리에 제공되는 클래스를 기반으로 감싼 클래스 형태로 만들고자 할 때 많이 사용됩니다. 만약, 감싼 클래스의 개체를 생성해서 사용할 때 기반 클래스의 public 메서드를 숨기게 되어 자신이 제공하는 public 메서드만 사용하게 됩니다. 그리고 private 상속은 파생받은 클래스를 기반으로 다시 파생받은 곳에서 원래 기반 클래스의 멤버에 접근하지 못하게 할 경우에 사용됩니다.
private 상속을 하는 예를 들어볼께요.
정수 값을 보관하는 IntArr 클래스가 이미 정의되어 있다고 가정을 합시다. 해당 클래스에는 맨 뒤에 보관하는 메서드와 특정 인덱스에 보관하는 메서드, 맨 뒤에 값을 얻어오는 메서드, 맨 앞에 값을 얻어오는 메서드 등 수 많은 메서드가 있을 것입니다. 이를 파생을 이용하여 스택을 만들려고 한다고 했을 때 public 상속을 하면 스택을 사용하는 곳에서 접근하면 안 되는 메서드들도 가시성이 있어 접근할 수 있게 됩니다. 이러면 사용하는 곳에서 접근해도 되는 메서드(Push, Pop, IsFull, IsEmpty)들을 만들어 접근 지정을 public으로 설정하고 대신 IntArr 클래스에서 private 상속을 하여 IntArr 클래스의 메서드를 사용자가 접근하지 못하게 막을 수 있습니다.
[그림 5.7]
IntArr.h |
#pragma once
#define MAX_ELEMENTS 100 class IntArr { int base[MAX_ELEMENTS]; int cnt; public: IntArr(void); virtual ~IntArr(void); bool PushBack(int val); int GetFront()const; bool PopFront(); int GetBack()const; bool PopBack(); int GetAt(int index)const; bool InsertAt(int index,int val); int GetCount()const; protected: bool IsFull()const; bool IsEmpty()const; bool AvailIndex(int index)const; };
|
IntArr.cpp |
#include "IntArr.h" #include <memory.h>
IntArr::IntArr(void) { cnt = 0; } IntArr::~IntArr(void) { }
bool IntArr::PushBack(int val) { if(IsFull()) { return false; } base[cnt] = val; cnt++; return true; } int IntArr::GetFront()const { return base[0]; } bool IntArr::PopFront() { if(IsEmpty()) { return false; } cnt--; memcpy(base,base+1,sizeof(int)*cnt); return true; } int IntArr::GetBack()const { return base[cnt-1]; } bool IntArr::PopBack() { if(IsEmpty()) { return false; } cnt--; return true; } int IntArr::GetAt(int index)const { return base[index]; } bool IntArr::InsertAt(int index,int val) { if(AvailIndex(index)==false) { return false; } base[index] = val; return true; } int IntArr::GetCount()const { return cnt; } bool IntArr::IsFull()const { return cnt==MAX_ELEMENTS; } bool IntArr::IsEmpty()const { return cnt==0; } bool IntArr::AvailIndex(int index)const { return (index>=0) && (index < MAX_ELEMENTS); }
|
EhStack.h |
#pragma once #include "intarr.h" class EhStack : private IntArr { public: bool Push(int val); int Pop(); bool IsFull()const; bool IsEmpty()const; };
|
EhStack.cpp |
#include "EhStack.h"
bool EhStack::Push(int val) { return PushBack(val); } int EhStack::Pop() { int val = GetBack(); PopBack(); return val; } bool EhStack::IsFull()const { return IntArr::IsFull(); } bool EhStack::IsEmpty()const { return IntArr::IsEmpty(); }
|
[그림 5.8]
[그림 5.8]은 기반 클래스에 접근 지정이 public으로 설정된 멤버 InsertAt에 접근하려고 할 때 오류가 나는 것을 확인할 수 있습니다. 다음은 정상적으로 사용하는 코드입니다.
Test.cpp |
#include "EhStack.h" #include <iostream> using std::cout; using std::endl; void main() { EhStack *ehstack = new EhStack(); ehstack->Push(3); ehstack->Push(7); cout<<ehstack->Pop()<<endl; cout<<ehstack->Pop()<<endl; delete ehstack; } |
(모든 동영상 강의는 무료입니다.)
'언어 자료구조 알고리즘 > Escort C++' 카테고리의 다른 글
[C++] 전역 연산자 중복 정의 (0) | 2016.04.15 |
---|---|
[C++] 연산자 중복 정의 (0) | 2016.04.15 |
[C++] 하향 캐스팅 (0) | 2016.04.15 |
[C++] 메서드의 다형성 (0) | 2016.04.15 |
[C++] 개체의 다형성 (0) | 2016.04.15 |
[C++] 무효화 된 멤버 사용하기 (0) | 2016.04.15 |
[C++] 무효화 (0) | 2016.04.15 |
[C++] 파생 개체 생성 과정 및 초기화 (0) | 2016.04.15 |
[C++] 일반화 관계와 파생 (0) | 2016.04.15 |
[C++] 실현관계 (Realization) (0) | 2016.04.15 |