일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- increment operator
- C++
- operator overloading
- virtual function
- pointer to member data
- c++ basic practice
- std::cout
- constructor
- discord bot
- this call
- virtual destructor
- vector capacity
- 더 지니어스 양면포커
- return by reference
- vector size
- placement new
- dynamic_cast
- member function pointer
- diamond inheritance
- conversion constructor
- base from member
- new&delete
- delete function
- suffix return type
- std::endl
- std::vector
- std::ostream
- c++ multi chatting room
- virtual inheritance
- virtual function table
- Today
- Total
I'm FanJae.
[C++] Static Member 본문
※ 본 포스트는 코드누리 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 (1) | 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 |