1. 정적 멤버 데이터 (static member data)
#include <iostream>
class Car {
int speed;
int color;
public:
Car() {}
~Car() {}
};
int main() {
Car c1;
Car c2;
Car c3;
}
① 객체의 생성과 소멸
=> 모든 객체는 생성 될 때 생성자를 호출하고
=> 모든 객체는 파괴 될 때 소멸자를 호출한다.
② 객체가 몇 개 생성되었는지 개수를 알고 싶다면
=> 생성자에서 변수 값을 +1
=> 소멸자에서 변수 값을 -1
③ 객체의 개수를 관리할 변수가 필요하다.
객체의 개수를 관리할 변수를 만들어보자
#include <iostream>
class Car {
int speed;
int color;
public:
int cnt = 0;
Car() { ++cnt; }
~Car() { --cnt; }
};
int main() {
Car c1;
Car c2;
Car c3;
std::cout << c1.cnt << std::endl;
}
위와 같이 코드를 짤 경우 문제는 뭘까?
우리는 현재 객체의 개수를 알고 싶으므로 출력 시 결과값이 3이 나와야 하지만 1이 나온다.
① 멤버 데이터를 사용해서 객체의 개수를 관리하는 경우
=> 멤버 데이터는 객체당 하나씩 별도의 메모리 공간 사용
=> 객체의 개수는 항상 1이다.
#include <iostream>
int cnt = 0;
class Car {
int speed;
int color;
public:
Car() { ++cnt; }
~Car() { --cnt; }
};
int main() {
Car c1;
Car c2;
Car c3;
std::cout << cnt << std::endl;
}
② 전역 변수를 사용해서 객체의 개수를 관리 하는 경우
=> 전역 변수는 메모리에 하나만 있고, 모든 객체가 공유
=> 모든 객체가 공유하므로 객체의 개수를 구할 수 있다.
=> 실수로 외부에서 cnt변수값을 변경한다면?
#include <iostream>
class Car {
int speed;
int color;
public:
static int cnt;
Car() { ++cnt; }
~Car() { --cnt; }
};
int Car::cnt = 0;
int main() {
Car c1;
Car c2;
Car c3;
std::cout << c1.cnt << std::endl;
}
① 객체의 개수를 관리하는 변수
=> 모든 객체가 공유해야 한다.
=> 외부에 잘못된 사용으로부터 보호할 수 있어야 한다.
② 정적 멤버 데이터 (static member data)
=> static이 붙은 멤버 데이터
=> 모든 객체가 공유한다.
=> 클래스 내부에 선언(declaration)을 만들고
=> 클래스 외부에 정의(definition)를 만들어야 한다.
#include <iostream>
class Car {
int speed;
int color;
static int cnt;
public:
Car() { ++cnt; }
~Car() { --cnt; }
int getCount() { return cnt; }
};
int Car::cnt = 0;
int main() {
Car c1;
Car c2;
Car c3;
std::cout << c1.getCount() << std::endl;
}
③ 정적 멤버 데이터의 특징
=> 모든 객체가 공유한다.
=> 멤버이므로 접근 지정자를 사용할 수 있다.
// Car.h
Class Car {
public:
int speed;
int color;
static int cnt;
public:
Car();
};
//----------
// Car.cpp
#include "Car.h"
int Car::cnt = 0;
Car::Car() {
}
① 정적 멤버 데이터를 만드는 방법
=> 클래스 안에 변수 선언부를 제공하고 클래스 외부(소스 파일)에 정의(definition)을 제공한다.
2. 정적 멤버 데이터와 일반 멤버 데이터
#include <iostream>
int cnt = 0;
Class Car {
public:
int speed;
int color;
static int cnt;
Car() {}
};
int Car::cnt = 0;
int main() {
}
3. 정적 멤버 데이터 접근 방법
class Car {
public:
int speed;
int color;
static int cnt;
};
int Car::cnt = 0;
int main() {
Car c;
c.speed = 0;
c.cnt = 0;
Car::cnt = 0;
}
① 일반 멤버 데이터에 접근하는 방법
=> 객체 이름으로만 접근 가능 -> c.speed
② 정적 멤버 데이터에 접근하는 방법
=> 객체 이름을 사용하거나 클래스 이름을 사용해서 접근할 수 있다.
=> 되도록이면 클래스 이름을 사용해서 접근하는 것이 좋다.
③ Java, C# 등의 언어는 클래스 이름으로만 접근 가능하다.
4. 정적 멤버 데이터의 초기화
class Test {
public:
int data = 0; // C++11부터 가능
// static int sdata1 = 0; // error
static int sdata1; // 선언(declaration)
static const int sdata2 = 0; // ok
static const double sdata3 = 0; // error
static constexpr int sdata4 = 0; // ok
static constexpr double sdata5 = 0; // ok
inline static int sdata6 = 0; // C++17부터
};
int Test::sdata1 = 0; // 정의(definition)
int main() {
int n1 = Test::sdata1;
int n2 = Test::sdata2;
int n3 = Test::sdata3;
int n4 = Test::sdata4;
int n5 = Test::sdata5;
int n6 = Test::sdata6;
}
① C++11부터 일반 멤버 데이터는 멤버 필드 초기화를 사용가능하지만
정적 멤버 데이터는 필드 초기화를 사용할 수 없다.
=> 클래스 외부에 정의(definition)에서 초기값을 지정해야 한다.
'프로그래밍 > C++' 카테고리의 다른 글
[C++] const member function (0) | 2019.11.17 |
---|---|
[C++] static member function (0) | 2019.11.17 |
[C++] 객체의 복사 방법 (0) | 2019.11.13 |
[C++] 복사 생성자 (copy constructor) (0) | 2019.11.07 |
[C++] explicit 생성자 (0) | 2019.11.06 |