본문 바로가기
카테고리 없음

인스턴스 멤버와 정적 멤버

by 가보자곳 2025. 6. 7.
반응형

클래스를 설계할 때는 인스턴스 멤버와 정적 멤버라는 2가지 멤버 그룹을 사용하므로

이를 이해하면 클래스를 더 잘 설계할 수 있다.

멤버 함수는 클래스 안에 정의된 모든 함수를 말한다.

그리고 이 모든 함수들은 인스턴스와 정적 두 가지로 분류된다.

 

인스턴스 멤버

인스턴스 데이터 멤버

인스턴스 데이터 멤버(instance data member)는 인스턴스의 속성을 정의한다

따라서 각각의 객체는 클래스에 정의된 데이터 멤버들을 캡슐화해야 한다

 

캡슐화라는 용어는 객체별로 메모리 영역을 할당하므로

각 영역에서 객체마다 서로 다른 데이터를 갖는 속성을 의미

 

즉, 이러한 데이터 멤버는 해당 인스턴스에만 속하므로 인스턴스끼리 서로 접근할 수 없다

 

 

인스턴스 데이터 멤버에는 private과 public이라는 접근 제한자를 적용할 수 있다

하지만 인스턴스 데이터 멤버는 일반적으로 private으로 설정하는 것이 좋다

만약 public으로 만들면, 멤버 함수를 호출하지 않고도 애플리케이션에서 데이터 멤버에 접근할 수 있는데

이는 객체 지향 프로그래밍의 기본적인 개념에 어긋난다

객체 지향 프로그래밍은 객체가 행위(멤버 함수)를 통해서 속성을 조작하는 것이 기본

 

인스턴스 멤버 함수

인스턴스 멤버 함수(instance member function)는 인스턴스의 행위를 의미한다

객체의 인스턴스 데이터 멤버를 조작하기 위해 사용한다

인스턴스 데이터 멤버는 모든 객체가 개별적으로 갖지만,

멤버 함수는 메모리 위에 하나만 올라가며 모든 인스턴스가 공유

 

인스턴스 데이터 멤버와 다르게 인스턴스 멤버 함수는 일반적으로 public 접근 제한자를 붙임

그래야 클래스 외부(애플리케이션 부분 등)에서 멤버 함수에 접근할 수 있고

그래야 private으로 선언된 데이터 멤버에 접근할 수 있기 때문이다.

 

물론 클래스 내부의 멤버 함수에서만 접근해야 하는 함수를 만들 때도 있고

이러한 특별한 경우에는 private 접근 제한자를 붙인다

 

그럼 멤버 함수 하나만 메모리에 올라간다면, 어떻게 여러 객체가 멤버 함수를 공유할 수 있을까?

어떤 객체가 멤버 함수를 사용하고 있을 때, 다른 객체가 멤버 함수를 사용하지 못하게 막는 것일까?

 

맞다.

다른 말로 표현하면 어떻게 어떤 객체가 함수를 사용하고 있을 때 잠그고(lock)

모두 사 용한 뒤에 다른 객체가 사용할 수 있도록 잠금을 해제(unlock) 하는 방식이다.

 

이를 위해서 멤버 함수에 this 포인터(객체의 주소를 나타내는 변수)를 지정하는 방법을 사용한다.

모든 멤버 함수에는 이와 같은 this 포인터가 숨겨져 있다

// 작성한 코드
double getRadius() const
{
	return radius;
}
// 컴파일러가 수정한 코드
double getRadius(Circle* this) const
{
	return (this -> radius);
}

클래스 Circle로 circle1 객체를 생성한 후에

circle1.getRadius()를 통해 멤버함수를 호출하면

멤버 함수의 this에 circle1의 주소를 할당하고

circle1에 초점을 맞춰 getRadius()를 진행하고 리턴하는 방식이다.

 

참고로

this -> radius
(*this).radius

위 두 코드는 완전히 같은 뜻이다.

 

// 사용자 작성
circle1.getRadius();
//시스템이 해석한 코드
this = &cirlce1;
getRadius(this);

우리가 평소에 저렇게 적으면

내부적으로 시스템에서 위와 같이 바꿔 해석한다는 의미이다.

물론 처음부터 시스템이 해석한 코드와 같이 작성해도 아무 문제없다.

 

용어를 몇가지 더 살펴보겠다.

호스트 객체는 인스턴스 멤버 함수를 호출하는 객체를 의미

this 포인터가 가리키는 객체가 바로 호스트 객체이다. 위에서는 circle1이 호스트 객체이다.

 

접근자 멤버 함수(accessor member function)는 호스트 객체의 정보를 추출(get) 할 때 사용하는 함수이다.

double getRadius() const;        // 호출한 객체는 읽기 전용입니다
double getPerimeter() const;     // 호출한 객체는 읽기 전용입니다
double getArea() const;          // 호출한 객체는 읽기 전용입니다

읽기 전용으로 만드는 const에 대해서는 다음 시간에 깊이 알아보겠다.

쨌든 위와 같이 정보를 그냥 추출하는 함수를 접근자 멤버 함수라고 한다.

 

반대로 정보를 추출하는 함수가 아니라 데이터 멤버를 변경하는 함수도 존재한다.

이런 함수는 설정자 멤버 함수(mutator member function)이며 셋터(setter)라고 부르기도 한다

void setRadius(double rds); // 멤버를 수정하는 함수에는 const를 붙이지 않습니다

주석과 마찬가지로

이 때 호스트 객체의 상태를 변경하므로 const 한정자를 붙이면 안된다.

 

설정자 인스턴스 멤버 함수의 역할은 데이터 멤버의 값을 변경하는 것이며

따라서 매개 변수가 없어도 데이터 멤버의 값을 변경한다면 설정자 함수이다

 

 

클래스를 디자인할 때 중요한 문제로 클래스 불변 속성이 있다

클래스 불변 속성이란 클래스의 모든 유효한 객체(instance)가 항상 만족해야 하는 조건

데이터 멤버의 일부 또는 전체에 적용해야 하는 하나 이상의 조건을 의미하며

인스턴스 멤버 함수를 사용해서 적용한다

Circle::Circle(double rds)
: radius(rds)
{
    if (radius <= 0.0) {
        cout << "유효하지 않은 반지름입니다. 원을 만들 수 없습니다!" << endl;
        cout << "프로그램을 종료합니다." << endl;
        assert(false); // 디버깅 중 강제 종료
    }
}

 

정적 멤버

그럼 이제는 정적 멤버에 대해 알아보겠다.

인스턴스 멤버와 마찬가지로 정적 멤버도 정적 데이터 멤버와 정적 멤버 함수로 구분한다.

 

정적 데이터 멤버

정적 데이터 멤버(static data member)는 클래스 또는 모든 인스턴스에 포함되는 멤버이다

class Rectangle
{
    private:
    	static int count; // 정적 데이터 멤버 
}

 

정적 데이터 멤버는 인스턴스에 속하는 것이 아니므로 생성자에서 초기화할 수 없다

클래스 정의 후에 초기화해야 하며 따라서 프로그램의 전역 영역에 서 초기화해야 한다.

일반적으로는 클래스 정의 바로 뒷부분의 전역 영역에 작성한다.

int Rectangle :: count = 0;		//정적 데이터 멤버 초기화

주의할 점은 static 한정자를 추가하면 안된다는 것이다.

 

정적 데이터 멤버는 일반적으로 private이므로 이에 접근할 수 있는 public이 적용된 멤버 함수가 필요하다

이때 사용되는 것이 정적 멤버 함수이다.

정적 멤버 함수

class Rectangle
{
    private:
    	static int count; // 정적 데이터 멤버
    public:
    	static int getCount(); // 정적 멤버 함수
}
int Rectangle :: getCount()
{
	return count;
}

이때도 static 키워드가 붙지 않는다.

 

정적 멤버 함수는 인스턴스 또는 클래스를 통해서 호출할 수 있다.

정적 멤버 함수는 인스턴스와 연결되지 않으므로, 호스트 객체가 없다

따라서 정적 멤버 함수 내부에서 인스턴스 데이터 멤버에 접근할 수는 없음

 

인스턴스 멤버 함수에서는 정적 데이터 멤버에 접근할 수 있지만

일반적으로 인스턴스 멤버 함수에서 정적 데이터 멤버에 접근하지 않음

인스턴스 멤버 함수인스턴스 데이터 멤버에 접근할 때,

정적 멤버 함수정적 데이터 멤버에 접근할 때 사용하는 것이 좋음

 

/**************************************************************
* 사각형(Rectangle) 객체를 생성하고 개수를 세는 프로그램 *
**************************************************************/
#include <iostream>
using namespace std;

/**************************************************************
* Rectangle 클래스 정의 *
**************************************************************/
class Rectangle
{
private:
    double length;
    double height;
    static int count; // 정적 데이터 멤버 (객체 수 카운트용)
public:
    Rectangle(double length, double height); // 매개변수 생성자
    Rectangle();                             // 기본 생성자
    ~Rectangle();                            // 소멸자
    Rectangle(const Rectangle& rect);        // 복사 생성자
    static int getCount();                   // 정적 멤버 함수
};

// 정적 데이터 멤버 초기화
int Rectangle::count = 0;

/***************************************************************
* 인스턴스 멤버 함수 정의 *
***************************************************************/

// 매개변수 생성자의 정의
Rectangle::Rectangle(double len, double hgt)
    : length(len), height(hgt)
{
    count++;
}

// 기본 생성자의 정의
Rectangle::Rectangle()
    : length(0.0), height(0.0)
{
    count++;
}

// 복사 생성자의 정의
Rectangle::Rectangle(const Rectangle& rect)
    : length(rect.length), height(rect.height)
{
    count++;
}

// 소멸자의 정의
Rectangle::~Rectangle()
{
    count--;
}

/***************************************************************
* 정적 멤버 함수 정의 *
***************************************************************/
int Rectangle::getCount()
{
    return count;
}

/***************************************************************
* Rectangle 객체를 생성하고 개수를 출력하는 main 함수 *
***************************************************************/
int main()
{
    {
        Rectangle rect1(3.2, 1.2);
        Rectangle rect2(1.5, 2.1);
        Rectangle rect3;
        Rectangle rect4(rect1);
        Rectangle rect5(rect2);
        cout << "현재 객체 수: " << rect5.getCount() << endl;
    }

    // 블록을 벗어나면서 객체들이 소멸됨
    cout << "main 함수 종료 직전 객체 수: " << Rectangle::getCount();
    return 0;
}
실행 결과:
현재 객체 수: 5
main 함수 종료 직전 객체 수: 0

 

위와 같이 생성자 소멸자에서도 정적변수에 접근할 수 있다.

 

 

반응형

댓글