클래스를 통해 여러 객체들을 만들다 보면, 하나의 클래스를 통해 생성된 여러 객체들에게 서로 공유가 가능한 데이터를 부여해야 할 때가 있다.
예를 들면, Monster 클래스를 통해 생성된 몬스터들의 수를 파악하고 싶을 때라고 해보자.
이 때, 생성될 때 마다 임의의 변수 monsterCount를 누적시켜 파악하려고 할 때의 코드의 예시를 만들어보자.
using System;
namespace Favor
{
class Monster
{
public int monsterCount;
public Monster(){ monsterCount++; }
}
internal class Program
{
static void Main(string[] args)
{
Monster mon1 = new Monster();
Monster mon2 = new Monster();
Monster mon3 = new Monster();
Console.WriteLine(mon3.monsterCount);
}
}
}
위에서는 생성자에 monsterCount를 누적시키는 기능을 통해, Monster 클래스 객체가 만들어질 때 마다 monsterCount가 늘어난다.
그래서 mon3의 monsterCount가 3이 되도록 만들고자 했다.
과연 위 코드의 출력값은 어떨까?
출력값은 1이다.
왜냐하면, monsterCount는 인스턴스 될 때 마다 새로 만들어지기 때문이다.
즉, mon1이 객체화 되었을 때, mon1의 monsterCount가 별개로 하나,
mon2가 객체화 되었을 때 mon2의 monsterCount가 별개로 하나,
mon3이 객체화 되었을 때 mon3의 monsterCount가 1의 값을 가진 별개의 monsterCount가 각각 하나씩 생긴 것이다.
이렇게 되면, 모두가 같은 값을 공유하는 것이 아닌, 같은 멤버를 각각의 것으로 가지고 있는 것이기 때문에 우리가 원하는 결과값이 아니다.
using System;
namespace Favor
{
class Monster
{
public static int count;
public Monster() { count++; }
}
internal class Program
{
static void Main(string[] args)
{
Monster mon1 = new Monster();
Monster mon2 = new Monster();
Monster mon3 = new Monster();
// count의 값 : 3
}
}
}
이를 해결하려면 정적 멤버를 사용하면 된다.
정적 멤버는 클래스가 객체화 될 때 마다 그 객체에 속하는 것이 아니라, 클래스에 가만히 정적으로 존재한다.
정적 멤버가 아닌 멤버들은 인스턴스 될 때 마다 해당 객체로 복사되어 그 객체의 멤버가 되지만, 정적 멤버는 우직하게 클래스의 한 켠을 지키고 있는다.
그렇기 때문에 위의 코드에서는 Monster가 인스턴스 될 때 마다 각자의 값이 되는 것이 아니라 본인의 값이 생성자를 통해 호출, 누적되어 count의 값이 3이 되었다.
정적 멤버는 객체화된 객체들이 값을 접근할 수 없으며, 오직 클래스 내부에서만 값의 수정과 접근이 가능하다.
이는 서로의 영역이 다르기 때문인데,
인스턴스 된 객체(위의 코드에서는 mon1, mon2, mon3이 이에 해당한다.)는 인스턴스 필드라고 불리우는 영역 안의 값에만 접근할 수 있다.
인스턴스 필드 안에 있는 것으로는 멤버 변수와 멤버 함수가 선언되는 곳을 말한다.
그렇기 때문에 인스턴스 필드가 아닌 정적 필드에 존재하는 정적 멤버에는 접근이 불가능한 것이다.
using System;
namespace Favor
{
class Monster
{
public static int count;
public Monster() { count++; }
}
internal class Program
{
static void Main(string[] args)
{
Monster mon1 = new Monster();
Monster mon2 = new Monster();
Monster mon3 = new Monster();
Console.WriteLine(mon1.count); // 런타임 에러.
Console.WriteLine(Monster.count); // 올바른 출력, 3이 출력
// count의 값 : 3
}
}
}
어려운 말이 반복적으로 나왔기에 조금 쉽게 말하자면,
인스턴스 필드는 클래스 내부의 영역이 아니라, 인스턴스 된 객체의 영역이다.
그러니까, Monster 클래스의 방이 아니라, mon1, mon2, mon3의 방이라는 것이다.
그리고 정적 멤버인 count는 클래스의 방에서 살고 있다.
따라서 count와 만나려면 mon1, mon2, mon3의 방에 가는 것은 의미없고, Monster의 방에 찾아가야 만날 수 있는 것이다.
그래서 count를 늘릴 때도 객체를 통해서가 아닌, 클래스에 있는 생성자를 통해 증가시켰다.
객체를 통해서는 바꿀수도, 접근할 수도 없다.
위의 코드도 mon1을 통해 count에 접근하려고 하면 런타임 에러가 발생한다.
count는 Monster에 살고있는데, mon1의 방을 찾아갔으니 찾지 못하는 것이 당연한 것이다.
이렇게 정적 멤버를 이용하여 클래스들이 서로 공유할 필요가 있는 정보를 다룰 수 있다.
'C# 일기' 카테고리의 다른 글
| 8. 클래스 상속 (0) | 2024.03.05 |
|---|---|
| 7. 프로퍼티(Property) (0) | 2024.03.05 |
| 5. 얕은 복사(Shadow Copy)와 깊은 복사(Deep Copy) (0) | 2024.03.05 |
| 4. 생성자 (Constructor) (0) | 2024.03.04 |
| 3. foreach문 (0) | 2024.03.04 |