1. 핵심 개념
- 상속 접근자( C++ Inheritance Access)
- Forward Declaration: 포인터나 참조만 가능(내일 정리)
- cpp 레퍼런스: 상수포인터 비슷한 대신 널불가, &연산으로 주소 구해도 원본 가리킴, 역참조(*) 자동화
- 포인터 배열과 배열 포인터((*ptr)[] vs *ptr[]: 배열을 가리키는 포인터 vs 포인터들의 배열)
- 상수 레퍼런스: 함수 매개변수에서의 복사 비용 방지 + 원본 보호; R-value 객체 수명연장
#include <iostream>
using namespace std;
class HeavyObject {
public:
HeavyObject() { cout << "객체 생성됨 (무거운 작업)\n"; }
~HeavyObject() { cout << "객체 소멸됨\n"; }
void doSomething() const { cout << "작업 수행 중...\n"; }
};
// 임시 객체를 값으로 반환하는 함수
HeavyObject createObject() {
return HeavyObject();
}
int main() {
cout << "[일반적인 호출]\n";
createObject();
// 반환된 임시 객체는 위 줄(statement)이 끝나는 즉시 소멸됨
cout << "위 줄에서 이미 소멸되었습니다.\n\n";
cout << "[상수 레퍼런스로 수명 연장]\n";
const HeavyObject& ref = createObject();
// 임시 객체가 바로 소멸하지 않고, 'ref'의 수명이 끝날 때까지 살아남음
ref.doSomething(); // 안전하게 접근 가능
cout << "main 함수 종료 직전...\n";
return 0;
} // 여기서 ref가 스코프를 벗어나며 임시 객체 소멸
r-value가 상수 레퍼런스로 수명이 연장되는 예시이다. 참조부분을 주석 처리하면 creadtObject()에서소멸한다.(참고로 *에 new로 힙에 생성한게 아니라서 스코프 벗어나면 소멸됨)
2. 상세 내용
2.1. C++ Inheritance Access
| Accessibility | Public Members | Protected Members | Private Memebers |
|---|---|---|---|
| Base Class | Yes | Yes | Yes |
| Derived Class | Yes | Yes | No |
C++에는 상속에도 접근제한자가 정의되어 있다. C#에는 없는 문법이라서 따로 학습을 위해 기록하겠다.
기본적으로 C++은 여타 객체지향 언어와 똑같이 위에 테이블의 접근제한자와 같이 부모-자식 간의 사용 범위를 결정해준다. 그런데 여기에 추가적으로 상속 단계에서 접근 제한자를 취해주면 외부에 부모 클래스의 멤버나 메서드를 비공개할 수 있다.
만약 private로 상속을 하는 경우 외부에서는 자식 클래스의 부모 클래스를 알 수 없게 한다. 이는 다음의 구현상 이점을 가진다.
- 부모로의 업캐스팅을 막는다.(부모 포인터에 암시적 변환 불가)
- Base* ptr = new PrivateDerived(); 컴파일 에러
- 오직 구현만을 빌려쓴다.(Implemented-in-terms-of)
protected로 상속을 하는 경우 기본적으로 private 상속과 같이 외부에서 접근이 불가하지만 추가적으로 자식 클래스를 상속받은 손자 클래스는 부모 클래스의 public, protected 접근할 수 있는 차이가 있다.
// public inheritance
#include <iostream>
using namespace std;
class Base
{
private:
int pvt = 1;
protected:
int prot = 2;
public:
int pub = 3;
// function to access private member
int getPVT()
{
return pvt;
}
};
class PublicDerived : public Base
{
public:
// function to access protected member from Base
int getProt()
{
return prot;
}
};
int main()
{
PublicDerived object1;
cout << "Private = " << object1.getPVT() << endl; // 1
cout << "Protected = " << object1.getProt() << endl; // 2
cout << "Public = " << object1.pub << endl; // 3
return 0;
}
위 코드는 public 상속 예시이다.
- 외부에서 부모 클래스의 멤버 접근이 불가하다(자식을 통해 경유함)
- 자식 클래스는 부모 클래스의 public, protected에 접근 가능
// protected inheritance
#include <iostream>
using namespace std;
class Base
{
private:
int pvt = 1;
protected:
int prot = 2;
public:
int pub = 3;
// function to access private member
int getPVT()
{
return pvt;
}
};
class ProtectedDerived : protected Base
{
public:
// function to access protected member from Base
int getProt()
{
return prot;
}
// function to access public member from Base
int getPub()
{
return pub;
}
// function to get access to private members from Base
int try_getPVT()
{
return Base::getPVT();
}
};
int main()
{
ProtectedDerived object1;
cout << "Private = " << object1.try_getPVT() << endl; // 1
cout << "Protected = " << object1.getProt() << endl; // 2
cout << "Public = " << object1.getPub() << endl; // 3
return 0;
}
위 코드는 protected 상속 예시이다.
- 외부에서 부모 클래스의 멤버 접근이 불가하다(자식을 통해 경유함)
- 자식 클래스는 부모 클래스의 public, protected에 접근 가능
#include <iostream>
using namespace std;
class Base
{
private:
int pvt = 1;
protected:
int prot = 2;
public:
int pub = 3;
// function to access private member
int getPVT()
{
return pvt;
}
};
class PrivateDerived : private Base
{
public:
// function to access protected member from Base
int getProt()
{
return prot;
}
// function to access public member
int getPub()
{
return pub;
}
// function to get access to private members from Base
int try_getPVT()
{
return Base::getPVT();
}
};
int main()
{
PrivateDerived object1;
cout << "Private = " << object1.try_getPVT() << endl; // 1
cout << "Protected = " << object1.getProt() << endl; // 2
cout << "Public = " << object1.getPub() << endl; // 3
return 0;
}
위 코드는 private 상속 예시이다.
- 외부에서 부모 클래스의 멤버 접근이 불가하다(자식을 통해 경유함)
- 자식 클래스는 부모 클래스의 public, protected에 접근 가능
private과 protected 상속은 자식-부모 클래스 간에는 연관이 없고 외부 코드에서는 똑같이 접근이 불가해서 비슷하지만 손자 클래스에서는 그 차이가 드러난다.
#include <iostream>
using namespace std;
class Base
{
private:
int pvt = 1;
protected:
int prot = 2;
public:
int pub = 3;
// function to access private member
int getPVT()
{
return pvt;
}
};
class ProtectedDerived : protected Base
{
};
class PrivateDerived : private Base
{
protected:
void backdoor() {
cout << prot << endl;
}
};
class GrandProtectedDerived : public ProtectedDerived {
public:
void Display() {
cout << prot << endl;
cout << pub << endl;
}
};
class GrandPrivateDerived : public PrivateDerived {
public:
void Display() {
// cout << prot << endl; 접근불가(protected inheritance)
// cout << pub << endl; 접근불가(protected inheritance)
backdoor();
}
};
int main()
{
GrandProtectedDerived object1;
GrandPrivateDerived object2;
object1.Display(); // 2\n3
object2.Display(); // 2
return 0;
}
protected 상속한 클래스를 상속한 손자 클래스는 조상 클래스에 접근이 가능한 모습이다. 직관적으로 어떤 때에 사용하는지는 솔직히 아직으로서는 와닿지 않는다.
[!NOTE] 정리
cpp에는 상속에도 제한자가 있다. 상속 제한자는 부모-자식(직계) 간에는 영향이 없는 대신에 외부 코드서는 protected나 private이면 부모 클래스에 접근이 불가능하다.
3. 질문 및 해결 (Q&A)
- 생성자 정의 오류
선언부에 Constructor Initialization List 쓰면 에러남 - 클래스 끝 세미콜론
- 전방선언 E0070: This error occurs in C++ when you attempt to use a pointer or reference to an incomplete type. An incomplete type is a type that has been declared but not fully defined, meaning the compiler does not know its size or structure.
- 헤더에 include 막하지 말기(중복 정의 막기)
- virtual std::string WhoAmI() = 0; 순수 가상함수가 아니면 기본 구현 필요함
4. 관련 문서 (Links)
- [[이전 관련 노트]]
- 참고한 외부 링크
- [상속 접근자](C++ Inheritance Access - GeeksforGeeks)
'내일배움캠프 > TIL' 카테고리의 다른 글
| TIL260504 - Quaternion (0) | 2026.05.04 |
|---|---|
| TIL260430 - CPP (0) | 2026.04.30 |
| TIL260428 - Unreal (0) | 2026.04.28 |
| TIL260427 - CPP (0) | 2026.04.27 |
| TIL260424 - CPP (0) | 2026.04.24 |