가상함수,순수가상함수,추상클래스,인터페이스
서론
항상 c++ 만 공부해 왔었기에 c#에 관한 내용은 무지했다. 하지만 Unity Engine은 C#으로 코딩하기 때문에 c#에 기초적인 내용은 알아야 한다.
개요
c++에 관해서는 가상함수, 순수가상함수, 추상클래스에 대한 개념을 알고 있었다.
가상함수란, 함수를 선언할 때 virtual이라는 keyword를 사용해 부모클래스에 있는 가상함수를 override 해서 자식함수에서 재정의 하여 쓰기 위해 사용된다.
가상함수 예시
class A {
public:
virtual void foo()
{
std::cout << "foo 함수 실행";
}
}
순수가상함수란, 함수를 선언할 때 virtual이라는 keyword와 함께 함수의 선언 끝에 = 0을 붙여준다. 또한, 함수에 대한 정의를 바로 해주지 않는다.
순수가상함수 예시
class A {
public:
virtual void foo() = 0;
private:
int a;
}
이러한 순수가상함수를 소유하고 있는 클래스를 우리는 추상클래스라 부른다.
추상클래스의 특징
- 순수가상함수를 소유한다.
- 추상클래스 자체를 객체로 생성할 수 없다.
- 다른 필드(변수), 메서드(함수) 필드(변수)를 가질 수 있다.
- 이 클래스를 상속받는 클래스는 반드시 순수가상함수에 대한 정의를 해야 한다.
인터페이스란, 오직 순수가상함수만 포함하고 있는 클래스이다.
인터페이스 예시
class IA {
public:
virtual void foo() = 0;
virtual void var() = 0;
}
이렇게 오직 순수가상함수만을 가지는 클래스를 인터페이스라고 부른다. 클래스의 이름 가장 앞에 I를 붙여주는 것이 관습이다.
인터페이스 특징
- 다른 필드(변수), 메서드(함수)를 가질 수 없다.
- 이 클래스를 상속받는 클래스는 반드시 모든 순수가상함수로 선언 되었던 함수에 대한 정의를 해야한다.
또한 추상클래스와 인터페이스의 설계 의도가 서로 다르다.
추상클래스는 "is - a"관계를 정의한다.
예를 들어서 Cat이라는 클래스가 Animal이라는 클래스를 상속한다면 Cat is an Animal이라고 할 수 있다.
반면에, 인터페이스는 "can - do"관계를 정의한다.
예를 들어 Car라는 클래스가 OpenDoor라는 인터페이스를 구현하고
Car라는 클래스가 move라는 인터페이스를 구현한다면,
car can open door가 성립한다.
car can move가 성립한다.
(문법상 옳지 않긴 하지만...)
이처럼 C++에서도 다중상속을 할 수가 있다.
본론
위에서 인터페이스와 추상클래스에 대해서 알아보았다.
c++에서도 있는 개념이지만 C#에서는 좀 더 구체화하여서 구현을 할 수 있다.
c++에서의 순수가상함수는 c#에서 추상(abstract) 함수이다.
따라서 표현법도
virtual void foo() = 0; -> public abstract void foo();
위처럼 달라진다.
일단 c#은 c++과 조금 다르게 접근지정자(public, protected, private)를 변수나 함수에 앞에 명시한다.
추상클래스에서 모든 추상 함수는 public이어야 하고 다른 변수나 함수는 private, protected 등의 접근지정자를 사용하여 선언할 수 있다. 또한 abstract라는 keyword를 쓸 수 있으므로 추상 함수를 가지는 클래스는 abstract keyword를 포함해서 추상클래스라고 명시한다.
abstract class AbstactClassTest
{
int num;
public void foo()
{
//something
}
virtual public void var()
{
//something
}
abstract public void abstractFoo();
}
c#에서의 인터페이스에서는 모든 함수가 추상함수이므로 모든 함수가 public 이여야 하고 때문에 명시하지 않아도 public이 적용된다. 또한 "inteface"라는 키워드를 직접 써서 명시할 수 있다. 나머지는 c++ 개념과 비슷하게 함수 선언만 포함할 수 있고, 모든 함수는 인터페이스를 상속하는 클래스에서 반드시 구현해야 한다.
또한 인터페이스는 다중 상속이 가능하다.
interface InterfaceA
{
void interfaceFoo();
}
interface InterfaceB
{
void interfaceVar();
}
class TestClass : InterfaceA, InterfaceB
{
//something
public void interfaceFoo()
{
//something
}
public void interfaceVar()
{
//something
}
}
아래는 c#에서 인터페이스와 추상 클래스를 함께 쓰는 코드의 예시이다.
using System;
interface IFlyable
{
void Fly();
}
abstract class Bird
{
public abstract void Eat();
public void Sleep()
{
Console.WriteLine("Bird is sleeping.");
}
}
class Sparrow : Bird, IFlyable
{
public override void Eat()
{
Console.WriteLine("Sparrow is eating.");
}
public void Fly()
{
Console.WriteLine("Sparrow is flying.");
}
}
결론
구분 | 인터페이스(Interface) | 추상클래스(abstract class) |
상속 | 다중 상속 가능 | 단일 상속만 가능 |
구현 여부 | 모든 메서드는 구현 없이 선언만 가능 | 일부 메서드는 구현 가능, 일부는 추상으로 선언 |
속성 및 필드 | 다른 필드(변수) 선언 불가능 | 필드(변수) 선언 가능 |
접근 지정자 | 메서드는 기본적으로 public, 지정 불가능 | 다양한 접근 지정자 사용 가능 (public, protected,private) |
사용 목적 | 행동 규약 정의, can - do | 공통 기능 제공 및 확장 |
생성자 | 생성자 정의 불가능 | 생성자 정의 가능 |
호출 방식 | 객체를 생성할 수 없으며 인터페이스로 호출 | 객체를 생성할 수 없으며 상속된 클래스로 호출 |
사용 시점 | 클래스 간의 공통된 동작만 정의할 때 사용 | 공통된 동작과 기본 구현을 함께 제공할 때 사용 |
마무리
익숙하지 않은 C#의 개념도 평소에 C++과 개념과 비교 정리 해두어서 생각하는 길을 여러 개 뚫어 놓자
위의 내용을 바탕으로 개발자 면접 간
1. C#에서 인터페이스와 추상클래스의 차이점은 무엇인가요?
2. 실제 게임을 개발할 때 인터페이스의 장점은 무엇인가요>
등에 대한 질문을 생각해 볼 수 있겠다. 스스로에게 질문을 해보고 답해보자.
헷갈리는 부분은 보완하기! 찡긋 O.<
틀린 부분이나 보완해줬으면 하는 내용이 있으면 댓글로 알려주세요! 추가 설명이 필요하신 부분도 댓글로 알려주세요.
어떠한 피드백도 환영입니다. 긴 글 읽어주셔서 감사합니다.