클래스의 특징
상속,은닉, 다형성에 대해 알아볼 것이다.
우선 상속성은 말 그대로 어떤 클래스의 변수나 함수를 상속받아서 다른 클래스에서도 사용할 수 있게하는 개념이다.
부모-자식으로 표현하자면 부모클래스가 가지고 있던 변수를 자식클래스가 상속한다면 자식클래스에서도 그 변수를 사용가능하게 된다.
class Person()
{
int hp;
public void Move();
}
class Student() : public Person
{
}
이런 식으로 상속이 가능하다.
그리고 이전 글에서 this키워드는 자기자신을 가리킨다고 했는데, base란 키워드도 있다. 이는 부모클래스를 가리키는 키워드이다.
그렇다면 이 상속이란 개념은 어디에 쓰일까
내 생각에는 우리가 함수를 만드는 것과 비슷하다고 생각한다.
함수를 만드는 이유는 특정기능을 여러번 사용하게 되면 그 코드를 여러번 작성해야하는데, 이를 해결하기 위해 따로 함수안에 코드를 작성한다. 그리고 그 기능을 사용할 때, 함수호출만으로 편하게 기능을 사용하기 위해 함수를 만든다.
클래스 상속도 비슷하다.
예를 들어, 플레이어와 몬스터, 수많은 몬스터를 각각 클래스로 만든다고 하자. hp, 공격력, 방어력 등은 모든 클래스에 필요하다. 또한 공격,방어,죽음 함수 등도 공통적으로 필요한 것들이다. 이러한 것들을 모든 클래스에 다 넣는 대신 좀 더 일반적인 클래스를 만들어 이러한 것들을 작성한다. 그리고 다른 클래스들은 이 클래스를 상속하기만 하면 된다.
다음은 은닉성이다.
클래스의 변수나 함수 중, 외부에서 접근하면 안되는 것들과 접근해도 되는 것들을 구분하기 위한 개념이다.
예를 들어, 아이디나 hp 등을 외부에서 바로 접근이 가능하게 한다면 버그나 오류가 많이 발생할 수도 있다.
이러한 것들도 방지하기 위함인 개념이다.
public, private, protected 키워드를 주로 사용한다.
public 은 외부에서도 접근이 가능하다는 의미다.
private은 클래스의 내부로직 즉, 멤버함수나 변수에서만 접근이 가능하다.
protected는 외부에서는 접근이 안되지만 상속받은 자식클래스에서는 접근이 가능한 것을 의미한다.
마지막은 다형성이다.
다형성은 말그대로 여러가지의 형체라는 뜻이다.
우선 상속관계에 있는 클래스간의 캐스팅과 그로인한 함수오버라이딩이 특징이다.
위에서 Person과 Student라는 클래스가 있다. 여기서 Person을 상속한 다른 직업들의 클래스도 여러개 만들었다고 해보자. 그 때, 다형성을 활용할 수 있다.
class Person
{
string name;
int id;
}
class Student : public Person
{
}
class Teacher : public Person
{
}
void Test(Person p)
{
bool p = (p is Teacher);
Teacher t = (p as Teacher);
}
static void Main()
{
Student p = new Student();
Teacher t = new Teacher();
Test(t);
}
위 코드는 Person을 상속받는 두개의 클래스가 존재한다. Test함수에 Teacher 타입의 변수를 매개변수로 넘겼을 때, 오류없이 p 변수에 t가 대입된다. 이 방식을 통해 좀 더 일반적인 함수제작이 가능해진다.
또, 만약 Teacher클래스에만 있는 멤버를 활용해야한다면 is나 as 키워드를 활용할 수 있다.
is 키워드는 bool 값을 리턴하는데 p 변수가 Teacher였는지 런타임에 확인하여 결과를 리턴한다.
as 키워드는 런타임에 p변수가 Teacher 타입이었다면 캐스팅을 해서 리턴해주고 아니었다면 null값을 리턴한다.
그리고 만약 위 세 클래스에 동일하게 걷는다란 함수가 있다고하자.
그럴 때 만약 상속받은 함수기능에서 추가나 변경한 즉, Student, Teacher 만의 재정의된 버전을 사용하고 싶다면
virtual, override 키워드를 사용하면 된다.
class Person
{
string name;
int id;
public virtual void Walk()
{
// Person 걷기 출력
}
}
class Student : public Person
{
public override void Walk()
{
// Student 걷기 출력
}
}
class Teacher : public Person
{
public override void Walk()
{
// Teacher 걷기 출력
}
}
다음과 같이 함수 오버라이딩을 통해 재정의가 가능하다. 그렇다면 만약 Person으로 캐스팅된 상태에서 Walk를 호출해도
런타임에서 확인하여 원래 타입의 오버라이딩 버전을 호출해준다.