I'm FanJae.

[C++] Static Member 본문

C++/Basic

[C++] Static Member

FanJae 2024. 8. 16. 23:46

※ 본 포스트는 코드누리 C++ Basic 강의 내용을 보고 정리한 포스트입니다.

 

- Car 객체를 몇개나 생성하는지 알아보고 싶다고 가정해보자.

- 멤버 데이터 count를 사용해서 시도했다.

#include <iostream>

class Car
{
    int speed{0};
public:
    Car() {}
    ~Car() {}
};

int main()
{
    Car c1;
    Car c2;
    
    std::cout << c1.count << std::endl;
}

- 멤버 데이터를 사용하면, 객체당 한 개가 생성된다.

- 각 객체가 독립적인 자신의 count 멤버 변수를 사용하므로 이 방법은 실패다.

 

- 이번엔, 전역변수 count를 사용해서 시도해보자

#include <iostream>

int count{0};
class Car
{
    int speed{0};
public:
    Car() {}
    ~Car() {}
};

int main()
{
    Car c1;
    Car c2;
    
    count = 100;
    
    std::cout << c1.count << std::endl; // 2
}

- 의도대로 만드는 데 얼추 성공한것 같았으나... .

 

문제점 1. 전역변수는 어디서나 접근할 수 있어 안전하지가 않다

- 이를 접근지정자 등으로 보호할 수 없을까?

문제점 2. Car 외의 다른 타입에도 동일한 기능(객체의 개수 파악)이 필요하다면?

- 또 다른이름의 변수를 사용해야한다. 이를 편하게 관리할 수 없을까?


1. static member data

#include <iostream>


class Car
{
	int speed{0};
public:
	static int count;

	Car()  {++count;}
	~Car() {--count;}
};
int Car::count{0}; // = 0

int main()
{
	Car c1;
	Car c2;

	std::cout << Car::count << std::endl; 							
}

- 멤버 데이터 앞에 static을 붙이는 문법이다.

- 반드시 클래스 외부에서 선언(정의)가 되어야 한다.

 

1-1. static member data 특징

- 프로그램이 처음 시작될 때(객체를 생성하지 않아도) 메모리에 놓이게 된다.

- 객체 생성시 static member data는 객체의 메모리에는 포함되지 않는다.

- 결국, 모든 객체가 Car::count를 공유하게 된다.

 

※ 즉, 접근 지정자를 사용할 수 있는 전역 변수와 같은 형태가 되는 것이다.

 

- 위 예제에서 int speed 변수는 객체당 한 개씩 생성된다. 이러한 변수를 'member data'라고 칭한다. (타 객체지향 언어에서는 instance field라고도 한다.)

- 한편, static int count는 클래스당 한 개씩 생성된다. 즉, 동일 타입의 모든 객체가 공유한다. 이러한 변수를 'static member data'라고 칭한다.

 

1-2. static member data에 접근하는 2가지 방법

#include <iostream>

class Car
{	
public:
	int speed{0};
	static int count;

	Car()  {++count;}
	~Car() {--count;}
};
int Car::count{0};

int main()
{
	Car c1;
	Car c2;
	c1.speed = 10;
	std::cout << c1.count   << std::endl; 	
	std::cout << Car::count << std::endl; // 이 방법을 많이 사용한다.														
}

- static 변수는 객체 이름으로 접근을 할 수 있고, 클래스 이름으로 접근이 가능하다.

- 하지만, 객체 이름으로 접근하면 구분이 어려워서 클래스 이름을 통해 접근하는 방법이 일반적이다.

- private 영역에 있는 경우, static 멤버함수로 접근한다.

 

1-3. static member data 관련 유의사항

① 선언과 구현을 분리 하는 경우

// Car.h
class Car
{
   int speed{0};
public:
   static int count;
   Car();
   ~Car();
};

// Car.cpp
#include "Car.h"

int Car::count{0};

Car::Car() { ++count; }
Car::~Car() { --count; }

- 클래스를 선언과 구현으로 분리를 할 경우, static 멤버 변수의 외부 선언은 구현파일(.cpp)에 있어야 한다.

 

다음의 경우에는 외부 선언 없이 클래스 내부에서 초기화가 가능하다.

- static const

- static constexpr

- inline variable (C++17)


2. static member function

#include <iostream>

class Car
{	
	int speed{0};
	static int count;
public:
	Car()  {++count;}
	~Car() {--count;}

	int get_count() { return count;}
};
int Car::count{0};

int main()
{
    Car c1
    Car c2;
    std::cout << c1.get_count() << std::endl; 
    
}

- 다음 예제는 static이 private의 있는 경우의 상황이다.

- 일반적으로는 member data가 private에 있을때는 member function을 사용해 접근한다.

문제는 static일 때만 발생하는 문제가 있다.

 

2-1. Car 객체를 생성하기 이전 상황

#include <iostream>

class Car
{	
	int speed{0};
	static int count;
public:
	Car()  {++count;}
	~Car() {--count;}

	int get_count() { return count;}
};
int Car::count{0};

int main()
{
    // std::cout << c1.get_count() << std::endl; 
    // 객체를 생성하기 전엔 Car 객체의 개수를 알 방법이 없는가?
    Car c1;
    Car c2;
}

- Car 객체를 생성하기 전에는 Car 객체의 개수를 확인할 방법이 없다.

- static member data는 객체가 생성되지 않아도 메모리에 존재한다.

- 하지만 member function은 호출을 하려면 반드시 객체가 있어야 한다.

 

※ 이럴때 객체 없이 private 멤버에 접근하기 위해서 객체 없이 호출 가능한 멤버 함수가 static member function이다. 

 

2-2. static member function

#include <iostream>

class Car
{	
	int speed{0};
	static int count;
public:
	Car()  {++count;}
	~Car() {--count;}

	static int get_count() { return count;}
};
int Car::count{0};

int main()
{
	// 여기서 Car 객체의 갯수를 알고 싶다.
	std::cout << Car::get_count() << std::endl; 

	Car c1;
	Car c2;
//	std::cout << c1.get_count() << std::endl; 
	std::cout << Car::get_count() << std::endl; 
}

- 이와 같이 static member function란, 객체 없이 호출 가능한 멤버 함수이다.

- 객체 이름 또는 클래스 이름으로 접근이 가능하지만, 보통은 클래스 이름으로 접근을 한다.


3. static member data vs global

- 전역 변수프로그램 처음 실행 시 메모리에 할당되고, 접근 지정자 사용은 불가능하다.

- static 멤버 데이터는 전역변수 처럼 프로그램 처음 실행시 메모리에 할당되고, 접근 지정자를 사용할 수 있다.

- 이에 반면 멤버 데이터는 객체를 생성하는 시점에 메모리에 할당되고, 접근 지정자 사용이 가능하다.

  메모리 할당 접근 지정자
전역 변수 프로그램 처음 실행 시 X
static 멤버 데이터 프로그램 처음 실행 시 O
non static 멤버 데이터 객체 생성 시  O

 

3-1. static member function vs global function

- 일반 함수는 객체 없이 호출이 가능하지만, private 멤버 데이터 접근이 불가능하다.

- static 멤버 함수는 객체 없이 호출이 가능하고, private 접근이 가능하다.

  메모리 할당 private 접근
일반 함수 객체 없이 호출 가능 X
static 멤버 함수 객체 없이 호출 가능 O
non static 멤버 함수 객체 생성 후 호출 가능 O

 

3-2. 선언과 구현 분리시 유의 사항

static 멤버 함수에서는 static 멤버(데이터, 함수)만 접근 할 수 있다.

※ 또한 static member data는 외부 정의는 구현 파일에 만들어야 한다. 이에 반면, static member function는 함수 선언부에만 static을 표기해야 함에 유의해야 한다.

 

 

'C++ > Basic' 카테고리의 다른 글

[C++] this, Reference return  (0) 2024.08.18
[c++] const member function, mutable  (0) 2024.08.17
[C++] Explicit Constructor  (0) 2024.08.14
[C++] Member initializer list, Default member initializer  (0) 2024.08.14
[C++] Vector I  (0) 2024.08.13
Comments