상속(4) - protected 멤버
Inheritance
◆ 상속의 정의
◆ 유도 클래스
◆ protected 멤버
◆ 상속에서의 생성자와 소멸자
◆ 기본 클래스의 생성자와의 관계
◆ 상속과 멤버 함수
protected 멤버에 대해 알아보자.
Protected Member
◆ Protected 멤버
● 기본 클래스에서 접근 가능
● 유도 클래스에서 접근 가능
● 기본 또는 유도 클래스의 객체로부터는 접근 불가능
☞ private. 클래스에서는 접근 가능하고, 객체로부터는 접근이 불가능하다.
☞ protected 는 "상속이 이뤄지는 private" 라고 생각하면 편하다.
☞ private 는 유도 클래스에서 접근이 불가능함에 유의하자
▶ private 은 상속과 관계없이 무조건 (자신) 클래스 내부에서만 접근 가능하다.
class Base {
protected:
// protected member
};
class 를 설명할때 access-specifier 접근제한자 이야기를 하면서
public , private 언급을 하였고,
protected 는 나중에 상속에서 배울거라고 언급하였다.
상속과 관련해서는 protected 접근 제한자를 멤버 변수나 멤버 함수에 걸어둘 수 있다.
protected 는 어떻게 동작하냐면
기본 클래스에서 접근이 가능하다.
유도 클래스에서도 접근이 가능하다.
기본 또는 유도 클래스의 객체로부터는 접근이 불가능하다.
class 에서는 접근이 가능하고 객체에서는 접근이 불가능한것이 원래는 private 이다.
#include <iostream>
using namespace std;
class Entity {
protected:
int x, y;
public:
Entity(int x, int y)
:x{ x }, y{ y } { }
};
class Player : public Entity
{
private:
int hp;
int xp;
int speed;
public:
Player(int x, int y, int speed)
:Entity{ x,y }, speed{ speed } {
}
void Move(int dx, int dy)
{
x += dx; y += dy;
}
void SetHP(int hp)
{
this->hp = hp;
}
};
int main()
{
Player p{ 5,5,10 };
p.HP = 10; // 컴파일 에러! private 로 되어 있기 떄문에 객체에서는 접근을 못하게 되어있다.
}
void SetHP(int hp)
{
// HP 객체로는 값을 변경할 수 없기때문에 멤버 함수를 사용하여 변경한다.
if (hp < 0) // 음수인 값은 대입을 못하게 막아둔다.
{
return;
}
this->hp = hp; // 음수가 아닌 경우에만 hp 값을 변경한다.
}
음수인 경우에는 return 하고 음수가 아닌 경우만 수정할 수 있도록 통로를 만들어 주는것이 안전하다.
private 에 존재 의미이다.
여기까지는 기존 class 에서 배웠던 내용이다.
객체에서는 접근 불가능하고, 클래스에서만 접근 가능한 애들이 private 이다.
protected 멤버도 비슷하다.
클래스에서는 접근 가능하지만 객체에서는 접근 불가능하다.
그럼 private 와 다른점은 무엇일까?
protected 은 상속이 이루어지는 private 라고 생각해봐야한다.
class Entity 에 멤버 변수는
protected int x, int y 로 되어있기 때문에
Player 클래스에서도 x 와 y에 값을 변경할 수 있었다.
(Player 클래스 Move 참고)
int main()
{
Player p{ 5,5,10 };
p.Move(1, -1); // 6,4 로 변한다.
}
Player 클래스의 멤버 함수인 Move() 안에서
x, y 에 접근할 수 있다.
x, y 는 Entity 클래스에 선언되어 있다.
Entity 의 멤버도 Player 에 포함이 되기 때문에
접근해서 값을 바꿀 수 있었다.
x, y가 private 으로 선언하였다면
Player::Move() 에서 x 와 y 를 선언할 수 없다.
class Entity {
private:
int x, y;
public:
Entity(int x, int y)
:x{ x }, y{ y } { }
};
// protected 는 클래스에서만 사용 가능하고 객체는 사용 못하기 때문에
int main()
{
Entity e{1,1};
e.x = 10; // 컴파일 에러!
Player p{ 5,5,10 };
p.x = 10; // 컴파일 에러!
}
protected 와 private 의 차이를 잘 알아두어야 한다.
private 은 유도 클래스에서도 접근이 불가능하며 상속과 관계없이 무조건 클래스 내부에서만 접근 가능하다.
중요한 Part이다.★★★★★
◆ Protected 멤버 변수
class Base
{
public:
int a;
protected:
int b;
private:
int c;
};
Base 클래스를 만들었고
public 변수 a
protected 변수 b
private 변수 c 가 있고
유도 클래스를 따로 만들었다.
유도 클래스 입장에서
멤버 변수 a 는 여전히 public 이다.
Drived d;
d.a = 10; // 만들 수 있다. public 이기 때문이다.
멤버 변수 b 는 protected 이기 때문에
d.b = 10; // 컴파일 에러가 난다.
대신 Drived 클래스 내부에서 멤버 변수 b 를 바꿀 수 있다.
멤버 변수 c 는 접근 불가이다.
멤버 변수 c 는 기본 클래스에서만 접근할 수 있는 private 이기 때문에
유도 클래스에서 접근이 불가능하다.
Drived 클래스 내부에서도 멤버 변수 c 를 바꿀 수 없다.
고급 Part이다.★★★
class Derived : public Base
{
public:
void SetValue()
{
cout << a << endl; // OK
cout << b << endl; // OK
cout << c << endl; // ERROR!
}
};
int main()
{
Derived d;
d.a = 1; //OK
d.b = 2; // ERROR!
d.c = 3; // ERROR!
cout << sizeof(Base) << endl; // 12 Bytes
cout << sizeof(Derived) << endl; // 12 Bytes
}
접근 할 수 없는 것이지, 값이 메모리에 저장되지 않는 것은 아닙니다.
Derived d 변수에
멤버 변수 a , b , c 가 모두 포함은 되어있다.
다만 값을 변경할 수 있는건 public 인 멤버 변수 a 이다.
멤버 변수 b 는 protected 이기 때문에
클래스 Derived 에서만 접근이 가능하고
객체에서는 접근이 불가능 하다.
당연히 멤버 변수 c 도 접근 불가능 하다.
sizeof 함수를 사용해서
객체가 차지하는 크기를 알 수 있다.
sizeof(타입) 을 선언하게 되면 타입이 얼만큼 크기를 차지하는지도
알 수 있었다.
sizeof(int) 경우 4 byte 이기 때문에 4가 출력된다.
sizeof(Base) 와 sizeof(Derived) 인 경우에는 12 byte 를 차지한다.
왜 12 byte 를 차지할까?
int 는 4 byte 를 차지한다.
그리고 실제로 어떤 클래스 객체를 만들게 되면은
멤버 변수들이 메모리 공간에 저장이 된다.
int 멤버 변수 3개를 가지고 있는 Base 와 Derived 클래스 내에 메모리 공간은 다음과 같다.
유도 클래스인 Derived 는 Base 멤버 객체를 가지고 있으면서 , 멤버 변수를 선언하지 않아서 12 byte 가 나온다.
왜 이 part 가 고급이냐면 헷갈릴수 있기 때문이다.
유도클래스 객체 d 에서
proteced 멤버 변수나 b나 provate 멤버 변수 c 에 접근할 수 없으나
접근할 수 없다고 해서 메모리 공간을 차지 안한다는 의미는 아니다.
Inheritance
◆ 상속의 정의 : 기본 클래스를 기반으로 새 클래스를 만드는 기능
◆ 유도 클래스 : 그렇게 만들어진 클래스를 유도 클래스라고 하며, 기본 클래스의 모든 것이 포함되어 있다.
◆ protected 멤버 : 상속에서 public 은 그대로, private 은 여전히 private 이므로, 정보를 숨기되 상속 계층의 하위로 데이터를 상속하고 싶을때는 protected 를 사용.
◆ 상속에서의 생성자와 소멸자
◆ 기본 클래스의 생성자와의 관계
◆ 상속과 멤버 함수
요약하자면
상속에서 public 은 그대로 public 이고,
private 는 private 이나, (자기 자신 클래스에서만 사용할 수 있다.)
객체에서는 사용할 수 없게 정보를 숨기되,
유도 클래스에서 접근하고 싶을때 protected 를 사용한다.
https://youtu.be/7zjvmceonXg?si=JsH2xmZYITyr06H_
예시코드가 없어서 오늘도 AI Claude 에게 protected 멤버 함수에 대해서 소스 코드와 설명을 요청하였다.
#include <iostream>
#include <string>
using namespace std;
class Person {
protected: // protected 멤버 변수
string name;
int age;
public:
// 생성자
Person(string n, int a):name(n) , age(a){}
// protected 멤버에 접근할 수 있는 protected 메서드
protected:
void displayBasicInfo() {
cout << "이름: " << name << ", 나이: " << age << endl;
}
};
class Student : public Person {
private:
string studentId;
public:
// 생성자
Student(string n, int a, string id)
: Person(n, a), studentId(id) { }
// 부모 클래스의 protected 멤버를 사용하는 메서드
void showStudentInfo() {
// protected 멤버인 name 과 age에 직접 접근 가능
displayBasicInfo();
cout << "학번: " << studentId << endl;
}
};
int main()
{
Student student("김영희", 20, "2025001");
// 상속된 protected 멤버 사용 예시
student.showStudentInfo();
// 직접 접근 불가능
//cout << student.name; // 컴파일 에러
return 0;
}
1. protected 멤버의 특징
■ private 보다 더 넓은 접근 범위를 가진다.
■ 해당 클래스와 이를 상속받은 자식 클래스 내에서만 접근 가능하다.
■ 외부에서는 직접 접근 할 수 없다.
2. 예제 설명
■ Person 클래스에서 name 과 age 를 protected 로 선언.
■ Student 클래스는 Person 를 상속받아 protected 멤버에 직접 접근 할 수 있다.
■ showStudentInfo() 멤버 함수에서 protected 멤버를 사용하고 있다.
주요 포인트
■ protected 멤버는 상속관계에서 유용한다.
■ 자식 클래스에서 부모 클래스의 protected 멤버를 자유롭게 사용할 수 있다.
■ 외부에서는 접근할 수 없어 데이터 은닉을 제공한다.
고마워 claude !