[공부] 261015 복습 / 인덱서 / Interface 무기장착
[이론]
추상화: 복잡한 현실의 몯느 세부사항을 생략하고 문제해결에 필요한 요소와 기능만을 담는것
클래스: 객체를 생성하기 위한 설계도
이 자체로는 동작하지 않고 이를 통해 변수를 만들고 값을 할당해야함
객체: 클래스를 기반으로 만들어진 실제 데이터와 동작의 결합체
추상클래스: 세부적은 구현은 자식에게 맡기고 본인은 최소한의 기능만 가지는 클래스
[인덱서(Indexer) ← 얜 대체 뭐야]
인덱서(Indexer) ← 배열도 아닌데 왜 []를 쓰지?
인덱서: 객체에
[]로 값을 요청할 수 있도록 만드는 기능
- 배열처럼 보이지만, 실제 배열일 필요는 없음
obj[2]를 호출하면 C#이 해당 객체에 선언된 인덱서를 찾아 실행함- 인덱서는 값을 저장하는 공간이 아니라, 값을 요청받았을 때 어떻게 반환할지 정하는 기능
- 메서드처럼 값을 반환할 수 있지만, 호출 문법이 다름
// 인덱서 선언
public int this[int index]
{
get { return index * 10; }
}
// 호출
int number = obj[2]; // index에 2가 전달됨 → 20 반환
인덱서는 this[int index] ← 왜 이름이 없지?
this는 인덱서를 선언할 때 사용하는 특별한 문법
int는 인덱서가 반환할 값의 자료형index는 대괄호 안에서 전달받을 값을 담는 매개변수- 인덱서 자체에는
Count같은 별도의 이름을 붙이지 않음. 객체에obj[번호]형태로 접근하기 때문 Count같은 다른 프로퍼티가 없어도 인덱서만 따로 만들 수 있음
public int this[int index]
{
get { return index * 10; }
}
인덱서는 여러 개 만들 수 있나?
한 클래스 안에 여러 인덱서를 선언할 수 있음
- 매개변수의 자료형이나 개수 등으로 구분할 수 있어야 함
- 반환형만 다르게 선언하는 것은 불가능
// 인덱서 선언
public int this[int index]
{
get { return index * 10; }
}
// 호출
int number = obj[2]; // index에 2가 전달됨 → 20 반환
//////////////////
obj[2]; // int를 받는 인덱서
obj["안녕"]; // string을 받는 인덱서
배열 vs
배열 vs 인덱서
배열은 실제 저장된 값을 읽고, 인덱서는 정의된 동작을 실행한다.
- 배열:
arr[1]→ 배열의 1번 위치에 저장된 값 - 인덱서:
obj[2]→ 인덱서의get실행 결과
// 배열: 실제 저장된 값 읽기
int[] arr = { 10, 20, 30 };
int number = arr[1]; // 20
// 인덱서: get의 계산 결과 반환
int number2 = obj[2]; // index * 10 → 20
인덱서 vs 메서드
둘 다 값을 반환할 수 있다. 차이는 주로 호출하는 문법과 용도다.
- 메서드: 작업이나 동작을 실행할 때 사용
- 인덱서: 객체의 값을 인덱스나 키로 조회·설정하는 형태에 적합
- 인덱서는 필수가 아님. 메서드로 구현해도 되는 경우가 많음
- 단, 인터페이스가 인덱서를 요구한다면 구현 클래스도 해당 인덱서를 구현해야 함
// 메서드
obj.GetValue(2);
// 인덱서
obj[2];
[Interface 무기 장착]
using System;
namespace ConsoleApp1
{
interface IAttackable
{
void Attack();
}
internal class InterWeapon
{
private IAttackable? _weapon = null;
class Sword : IAttackable
{
public void Attack()
{
Console.WriteLine("검 공격");
}
}
class Gun : IAttackable
{
public void Attack()
{
Console.WriteLine("총 공격");
}
}
class Staff : IAttackable
{
public void Attack()
{
Console.WriteLine("지팡이 공격");
}
}
public void Equipment(IAttackable weapon)
{
_weapon = weapon;
Console.WriteLine("무기를 장착했습니다.");
}
public void Attack()
{
if (_weapon == null)
{
Console.WriteLine("먼저 무기를 장착하세요.");
return;
}
_weapon.Attack();
}
static void Main(string[] args)
{
InterWeapon player = new InterWeapon();
Console.WriteLine("무기 선택: 1. 검 / 2. 총 / 3. 지팡이");
int wNum = int.Parse(Console.ReadLine());
switch (wNum)
{
case 1:
player.Equipment(new Sword());
break;
case 2:
player.Equipment(new Gun());
break;
case 3:
player.Equipment(new Staff());
break;
default:
Console.WriteLine("잘못된 무기 번호입니다.");
return;
}
Console.WriteLine("Enter를 누르면 공격합니다.");
Console.ReadLine();
player.Attack();
}
}
}
- interface IAttackable 선언
- private IAttackable? _weapon = null;
IAttackable?:null일 수도 있다고 타입에 표시= null: 선언하는 순간 실제 초기값을null로 지정
- class Sword : IAttackable들 인터페이스 구현
- public void Equipment(IAttackable weapon)
- 매개변수로 무기타입을 받음
- weapon = weapon; - 위에서 _weapon이걸 인터페이스 담는 공간으로 선언해서 무기 정보 받음
- _weapon.Attack(); 공격 실행 지금 무기에 담긴 공격 실행함
- InterWeapon player = new InterWeapon();
왜 객체를 생성하냐면, 네가 작성한 `Equipment()`와 `Attack()`은 `static`이 없는 인스턴스 메서드이기 때문이야. 즉, 특정 `InterWeapon` 객체를 대상으로 무기를 장착하고 공격하도록 만든 거야. 예를 들어 플레이어 객체를 두 개 만들 수도 있어.
InterWeapon변수에 담을 객체의 타입
player변수 이름
new InterWeapon()InterWeapon객체를 생성
- player.Equipment(new Sword());
- 이것도 세 부분으로 나눌 수 있어.
| 코드 | 의미 |
|---|---|
player | 메서드를 실행할 객체 |
.Equipment(...) | 그 객체의 Equipment() 메서드를 호출 |
new Sword() | 새 검 객체를 생성해서 인자로 전달 |
실행 순서는 다음과 같아.
new Sword()
검 객체 생성
player.Equipment(검 객체)
player의 메서드에 검 객체 전달
_weapon = weapon;
player가 사용하는 무기로 연결



