내일배움캠프/TIL

TIL260429 - CPP

옆집히드라 2026. 4. 29. 20:23

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)


'내일배움캠프 > 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