C++ 클래스와 객체: 기본 개념 및 핵심 기능

클래스와 객체

1. 클래스의 정의

C++은 C 언어에 객체지향 프로그래밍을 추가했으며, 이와 밀접한 개념이 클래스와 객체입니다.

클래스(class)는 사용자가 정의하는 사용자 정의 데이터 타입으로, 데이터와 함수를 캡슐화합니다. 클래스 내 데이터멤버 변수 또는 속성, 함수멤버 함수 또는 메서드라 합니다.

C의 구조체(struct)와 유사하지만, 클래스는 함수 캡슐화가 가능합니다. 이는 스택, 큐 등 자료구조 구현에 유리합니다.

class Rectangle {
public:  // 접근 지정자
    int calculateArea(int w, int h) {  // 면적 계산
        return w * h;
    }
private:
    int _width;   // 너비
    int _height;  // 높이
};

접근 지정자는 멤버의 접근 권한을 제어합니다:

  • public: 클래스 외부에서 직접 접근 가능
  • private: 클래스 외부에서 접근 불가
  • protected: 외부 접근 불가 (상속 시 활용)

일반적으로 멤버 변수는 private, 공개 함수는 public으로 선언합니다. C++의 struct도 클래스 역할을 하며, 차이점은:

  • class: 기본 접근 권한 private
  • struct: 기본 접근 권한 public

2. 객체 인스턴스 생성

클래스는 객체 생성을 위한 템플릿입니다. 객체 생성 시 인스턴스화라 하며, 이때 메모리가 할당됩니다. 클래스 정의 시 멤버 변수는 선언만 되며, 객체 생성 시 실제 메모리 공간이 할당됩니다.

3. 객체 크기 계산

객체 크기는 C 구조체의 메모리 정렬 규칙을 따릅니다. 크기 계산은 멤버 변수에만 의존하며, 멤버 함수는 포함되지 않습니다. 멤버 함수는 공용 코드 영역에 저장되어 모든 객체가 공유하기 때문입니다.

예외 사항:

  • 멤버 변수가 없거나 빈 클래스: 크기 1바이트 (객체 존재 표시용)

4. 암시적 this 포인터

동일한 멤버 함수를 서로 다른 객체가 호출할 때, this 포인터로 객체를 구분합니다. 컴파일러는 멤버 함수 호출 시 첫 번째 매개변수로 현재 객체를 가리키는 this 포인터를 자동 추가합니다.

// 실제 컴파일 후 함수 형태
void init(Rectangle* const this, int w, int h);

this 포인터는 함수 내부에서 사용 가능하지만, 매개변수에 명시적으로 작성할 수 없습니다.

클래스의 기본 멤버 함수

기본 멤버 함수는 명시적 구현이 없을 때 컴파일러가 자동 생성하는 함수입니다. 주요 4가지 함수를 중점적으로 다룹니다.

1. 생성자

객체 초기화를 담당하는 특수 멤버 함수입니다.

  • 이름: 클래스명과 동일, 반환형 없음
  • 객체 생성 시 자동 호출
  • 기본 생성자: 매개변수 없음, 전체 기본값 생성자, 컴파일러 생성자 포함
class Point {
public:
    Point(int x = 0, int y = 0) : _x(x), _y(y) {}
    void print() const {
        cout << _x << ", " << _y;
    }
private:
    int _x, _y;
};

컴파일러 생성 생성자는:

  • 기본 타입: 초기화하지 않음 (임의 값)
  • 사용자 정의 타입: 해당 타입의 기본 생성자 호출

2. 복사 생성자

기존 객체로 새 객체를 초기화하는 생성자입니다.

  • 첫 매개변수: 반드시 참조 타입 (값 전달 시 무한 재귀 발생)
  • 컴파일러 생성 복사 생성자는 얕은 복사 수행
  • 동적 메모리 사용 시 반드시 직접 구현
class Vector {
public:
    Vector(const Vector& v) : _size(v._size) {
        _data = new int[_size];
        memcpy(_data, v._data, _size * sizeof(int));
    }
private:
    int* _data;
    size_t _size;
};

3. 소멸자

객체 소멸 시 리소스 해제를 담당합니다.

  • 이름: ~클래스명, 매개변수/반환형 없음
  • 컴파일러 생성 소멸자는:
    • 기본 타입: 처리 안 함
    • 사용자 정의 타입: 해당 타입의 소멸자 호출
  • 동적 메모리 사용 시 반드시 직접 구현
class Buffer {
public:
    ~Buffer() {
        delete[] _buf;  // 할당된 메모리 해제
    }
private:
    char* _buf;
};

4. 대입 연산자 오버로딩

기존 객체 간 값 복사를 처리합니다.

  • 반드시 멤버 함수로 구현
  • 컴파일러 생성 버전은 얕은 복사 수행
  • 매개변수: const 참조 타입 권장
  • 반환값: \*this 참조 (연속 대입 지원)
Matrix& operator=(const Matrix& m) {
    if(this != &m) {  // 자기 할당 방지
        _rows = m._rows;
        _cols = m._cols;
    }
    return *this;
}

5. 핵심 원칙

동적 리소스 사용 시 복사 생성자, 소멸자, 대입 연산자를 반드시 함께 구현해야 합니다.

6. const 멤버 함수와 주소 연산자

const 멤버 함수는 함수 끝에 const를 붙여 선언하며, 객체의 상태를 변경하지 않음을 보장합니다.

void display() const {
    cout << _value;  // 멤버 수정 불가
}

주소 연산자 오버로딩은 일반적으로 컴파일러 생성 버전을 사용합니다. 특수한 경우에만 직접 구현합니다.

// 기본 구현
Data* operator&() { return this; }
const Data* operator&() const { return this; }

태그: C++ 클래스 객체지향 생성자 소멸자

7월 7일 06:09에 게시됨