C# - 객체 지향 기본 철학

Claire·2024년 10월 21일

객체지향

객체 지향이란?

  • 객체: Object, '사물'을 나타내는 추상적인 개념
  • 지향: Oriented, '지향하는'을 의미

    세상에 존재하는 모든 사물을 프로그래밍을 통해서 정의하고 만들어 낼 수 있다는 의미

객체 지향 프로그래밍 방식의 기능 단위는 '객체'이며, 사용자의 요청에 의해 처리되는 구조로, 대표적인 예는 모든 위도우 프로그램이다.

추상화

  • 추상: 대상에서 특징만을 뽑아낸 것

캡슐화

: 캡슐화는 외부에서 그 내부를 볼 수 없게 한다는 의미로, 데이터를 외부로부터 숨긴다는 데이터 추상화와 일맥 상통하는 개념이다.
그러나 마냥 데이터를 숨기기만 한다면 데이터를 사용할 수 없기에 무용지물이 될 수 있으므로, 외부로부터 데이터를 조작할 인터페이스가 필요하다.

클래스(Class)

클래스(Class): 학급

: 사용자 정의 데이터형으로 데이터와 메소드를 사용자인 내가 새로 정의한 데이터형이기 때문에 클래스를 추상적인 데이터형이라고 한다.
클래스의 본질은 결국 데이터형(Data Type)이라는 점이다.

클래스의 구성

  • 멤버 변수는 데이터 속성으로 보여지는 속성이고, 메소드는 행위나 행동(=기능)이라고 할 수 있다.
    개의 경우로 예를 들어보면 멤버 변수는 강아지의 눈, 코, 입, 귀, 다리 4개 등등을 의미한다면, 메소드는 달린다, 짖는다, 먹는다, 잔다 등을 나타내는 요소라고 보면 된다.
사물상태(필드)행동(메소드)
사람피부색, 키, 나이, 성별, 이름 등생각한다, 공부한다, 말한다, 걷는다 등
배기량, 차종, 연료의 종류 등달린다, 멈춘다, 짐을 싣는다 등
노트북CPU, 메모리 크기, 하드디스크 용량 등부팅한다, 충전한다, USB등을 읽어온다 등

=> 이와 같이 사물의 특성을 정리하여 필드와 메소드로 표현하는 과정이 추상화이고, 추상화된 결과를 하나의 클래스에 포함시키고 스스로 보호하는 것을 캡슐화라고 한다.

class 클래스 이름                               // 클래스 선언
{
	접근 지정자 클래스 이름() {...}                // 생성자
    접근 지정자 ~클래스 이름() {...}              // 소멸자
    접근 지정자 데이터형 멤버 변수(필드)() {...}     // 변수 선언
    접근 지정자 데이터형 메소드() {...}           // 메소드 선언
}

클래스 선언 시, class 키워드 써주고ㅡ 그 뒤에 클래스 이름을 붙인다
클래스의 요소로는 생성자, 소멸자, 멤버변수, 메소드 등으로 구성된다.
소멸자의 경우 닷넷 프레임워크에서 가비지컬렉션 기능이 동작하므로 선언하지 않아도 자동으로 소멸된다.

다형성(Polymorphism)

: 함수의 이름이 같더라도 전달 인자의 타입이나 개수 등에 따라 구분되는 것

  • C#에서는 오버로딩과 오버라이딩 기법이 있다.

오버로드(overloading)

사전적 의미는 "과적하다", "적재하다"라는 의미로, 겉모습은 똑같지만 내용이 다른 경우를 의미한다. 즉, 이름이 같은 함수일지라도 전달인자 타입이나 개수가 다른 경우이다.

int Plus(int a, int b) 
{
	return a+b;
}

char Plus(char a, char b) 
{
	return a+b;
}

double Plus(double a, double b) 
{
	return a+b;
}

C#으로 오버로딩 구현하기

namespace overloading
{
    public class Zerg {
        public Zerg() { }
        public void Overload(int zerggling)
        {
            Console.WriteLine("저글링 {0}마리", zerggling);
        }
        public void Overload(char zerggling)
        {
            Console.WriteLine("저글링 {0}등급", zerggling);
        }
        public void Overload(int zerggling, int hydra)
        {
            Console.WriteLine("저글링 {0}마리, 히드라 {1}마리", zerggling, hydra);
        }
        public void Overload(int zerggling, int hydra, int lurker)
        {
            Console.WriteLine("저글링 {0}마리, 히드라 {1}마리, 럴커 {2}마리", zerggling, hydra, lurker);
        }

    }

    internal class Program
    {
        static void Main(string[] args)
        {
            Zerg zerg = new Zerg();
            zerg.Overload(100);
            zerg.Overload('A');
            zerg.Overload(100, 50);
            zerg.Overload(100, 50, 50);
        }
    }
}

결과

오버라이딩(override)

: 오버라이딩은 사전적으로는 '위로 올라탄다', '엎어진다'는 뜻으로, 무언가에 올라타서 기존의 것을 덮어 버린다는 것을 의미한다. 이는 상속의 개념이 기반이 되어야 한다.

가상 키워드

상속받은 클래스의 메소드를 재정의하도록 할 때 부모 클래스의 메소등 virtual 키워드를 사용하며, virtual 키워드가 붙어 있는 메소드를 가상 메소드라고 한다.

가상 메소드로 정의한 메소드를 상속 받아 자식 클래스에서 override 키워드를 붙여 재정의하며, 재정의되는 메소드는 부모클래스의 가상 메소드 원형과 완전히 동일해야한다.

namespace firstClass
{
    public class Dog
    {
        private int eyes, nose, mouse, ears;
        public Dog()
        {
            eyes = 2;
            nose = 1;
            mouse = 1;
            ears = 2;
        }
        virtual public void bark()
        {
            Console.WriteLine("BowWow");
        }
    }
    public class Puddle : Dog
    {
        public override void bark()
        {
            Console.WriteLine("푸들푸들");
        }
    }

    internal class Program
    {
        static void Main(string[] args)
        {
            Dog dog = new Dog();
            dog.bark();

            Puddle puddle = new Puddle();
            puddle.bark();

            dog = new Puddle();
            dog.bark();
        }
    }
}

위 예시 코드에서 Dog 클래스에 bark라는 가상 메소드를 선언하고 해당 클래스를 자식인 Puddle클래스가 상속받아 오버라이딩함으로써 메인함수에서 dog = new Puddle()로 객체를 생성하여 dog.bark()메소드를 호출하고있음에도 불구하고 결과는 푸들푸들이라고 하는 자식 클래스의 메소드가 호출되는 것이다.

이러한 오버라이딩 기법을 사용하는 이유는 상속받는 자식 클래스마다의 기능을 다르게 재정의하여 사용할 수 있으며, 코드를 재사용할 수 있기 때문이다.
예를 들어, 외부에서 내가 자식클래스로 Puddle이 아닌 치와와라던지 울프독이라던지 허스키를 줄 때마다 각 클래스는 부모의 함수를 상속받아 각자의 기능으로 재정의하여 사용할 수 있기 때문이다.
(dog = new (자식 클래스)에 어떤 자식 클래스가 오느냐에 따라 호출된 dog.bark()의 결과값이 달라진다)

profile
SEO 최적화 마크업 개발자입니다.

0개의 댓글