06
04

1) 클래스 간의 형 변환

클래스 간의 형 변환은 explicit, implicit 메서드를 정의하는 것으로 가능하다. 예를 들어 Yen 타입에서 Won 타입으로 대입하고 싶다면 implicit 연산자를 사용해 구현할 수 있다. implicit operator를 오버로드 한다면 암시적 형 변환을 할 수 있고, 암시적 형 변환이 가능하다면 명시적으로 캐스팅 연산자를 쓰는 것도 허용된다.

하지만 개발자가 의도한 형 변환만 가능하도록 제한을 걸고 싶다면 implicit 대신 explicit 연산자를 제공해야 한다.

 

ex)

public class Currency
{
	decimal money;
	public decimal Money
	{ 
		get { return money; } 
	}

	public Currency(decimal money)
	{
		this.money = money;
	}
}

public class Won : Currency
{
	public Won(decimal money) : base(money)
 	{
	}

	public override string ToString()
	{
		return Money + "Won";
	}
}

public class Dollar : Currency
{
	public Dollar(decimal money) : base(money)
	{
	}

	public override string ToString()
	{
		return Money + "Dollar";
	}

	public static explicit operator Won(Dollar dollar)
	{
		return new Won(dollar.Money * 1000m);
	}
}

public class Yen : Currency
{
	public Yen(decimal money) : base(money)
	{
	}

	public override string ToString()
	{
		return Money + "Yen";
	}

	public static implicit operator Won(Yen yen)
	{
		return new Won(yen.Money * 13m);
	}
}

class Program
{
	static void Main(string[] args)
	{
		Won won = new Won(1000);
		Dollar dollar = new Dollar(1);
		Yen yen = new Yen(13);

		Console.WriteLine(won);
		Console.WriteLine(dollar);
		Console.WriteLine(yen);

		won = yen;
		//won = (Won)yen;
		Console.WriteLine(won);

		// won = dollar; // 오류
		won = (Won)dollar;
		Console.WriteLine(won);
	}
}

 

예제 실행 화면

 

2) 중첩 클래스(nested class)

중첩 클래스는 클래스 내부에 또 다른 클래스를 정의하는 것이다. 특정 클래스는 다른 구성 요소에 재사용되기보다는 일정한 클래스 전용으로 내장되어 사용되기도 한다. 하지만 클래스를 나누어 정의하면 다른 클래스에서 사용되어 실수할 여지를 남길 수 있다. 따라서 중첩 클래스를 사용하여 클래스 내부로 정의를 제한하는 것이 좋다. 중첩 클래스는 접근 제한자가 생략되면 다른 멤버와 마찬가지로 private이 지정되어 외부에서 인스턴스를 직접 생성하는 것이 불가능해진다. 중첩 클래스를 외부에서 사용하고 싶다면 명시적으로 public 접근 제한자를 지정해야 한다.

 

public class HardDisk
{
	class Platter
	{
	}
    
	class Head
	{
	}
    
	Platter[] platter;
	Head head;
}

 

3) 추상 클래스(abstract class)

부모 클래스의 인스턴스를 생성하지 못하게 하면서 특정 메서드에 대해 자식들이 반드시 재정의하도록 강제하고 싶은 경우가 존재한다. 이 때는 추상 클래스(abstract class)와 추상 메서드(abstract method)를 사용하면 된다. 추상 메서드는 abstract 예약어가 지정되고 구현 코드가 없는 메서드를 말한다. 추상 메서드는 일반 클래스에 존재할 수 없으며, 반드시 추상 클래스 안에서만 선언할 수 있다. 추상 메서드에는 접근 제한자로 private을 지정할 수 없다. 추상 클래스와 일반 클래스의 차별점은 new를 사용해 인스턴스로 만들 수 없다는 것과 추성 메서드를 가질 수 있다는 것이다. 추상 클래스를 상속받은 자식 클래스가 추상 메서드를 오버라이딩 안 할 경우 자식 클래스도 추상 클래스가 된다.

 

ex)

class Point
{
	int x, y;

	public Point(int x, int y)
	{
		this.x = x; this.y = y;
	}

	public override string ToString()
	{
		return "X: " + x + ", Y: " + y;
	}
}

abstract class DrawingObject
{
	public abstract void Draw();

	public void Move()
	{
		Console.WriteLine("Move");
	}
}

class Line : DrawingObject
{
	Point pt1, pt2;
	public Line(Point pt1, Point pt2)
	{
		this.pt1 = pt1;
		this.pt2 = pt2;
	}

	public override void Draw()
	{
		Console.WriteLine("Line " + pt1+ " ~ " + pt2);
	}
}

class Program
{
	static void Main(string[] args)
	{
		DrawingObject line = new Line(new Point(10, 10), new Point(20, 20));
		line.Draw();
	}
}

 

예제 실행 화면

 

4) 델리게이트(delegate)

C#에서는 델리게이트(delegate)라는 예약어로 메서드를 가리킬 수 있는 타입을 제공한다. 델리게이트는 메서드를 가리키는 변수(메소드 참조 변수)로 메서드의 위치(주소)를 가지고 있다. 델리게이트로 메서드를 가리키려면 반환 타입과 인자가 같아야만 한다. 시그니처가 동일한 메서드라면 인스턴스/정적 유형에 상관없이 모두 가리킬 수 있다.

접근제한자 delegate 대상_메서드의_반환타입 식별자(...대상_메서드의_매개변수_목록...);

 

ex)

class Program
{
	delegate void CarDeal();
	delegate void CarDeal2(int num);

	static void Car()
	{
		Console.WriteLine("test");
	}

	static void Ottogi()
	{
		Console.WriteLine("오뚜기");
	}

	static void Car2(int num)
	{
		Console.WriteLine("test2 " + num);
	}

	static void Main(string[] args)
	{
		Car();
		CarDeal Dealer;
		Dealer = Car;
		Dealer();
		Dealer = Ottogi;
		Dealer();
		// Dealer = Car2; 타입이 일치하지 않아 오류

		CarDeal2 Dealer2;
		Dealer2 = Car2;
		Dealer2(100);
	}
}

 

예제 실행 화면

 

델리게이트가 타입이라는 점은 중요하다. 변수가 사용되는 곳이라면 델리게이트 또한 함께 사용될 수 있다.

  • 메서드의 반환값으로 델리게이트(메서드)를 사용할 수 있다.
  • 메서드의 인자로 델리게이트(메서드)를 전달할 수 있다.
  • 클래스의  멤버로 델리게이트(메서드)를 정의할 수 있다.

 

 

ex)

 

public class Mathematics
{
	delegate int CalcDelegate(int x, int y);

	static int Add(int x, int y) { return x + y; }
	static int Subtract(int x, int y) { return x - y; }
	static int Multiply(int x, int y) { return x * y; }
	static int Divide(int x, int y) { return x / y; }

	CalcDelegate[] methods;

	public Mathematics()
	{
		// static 메서드를 가리키는 델리게이트 배열 초기화
		methods = new CalcDelegate[] { Mathematics.Add, Mathematics.Subtract, Mathematics.Multiply, Mathematics.Divide };
	}

	public void Calculate(char opCode, int operand1, int operand2)
	{
		switch (opCode)
		{
			case '+':
				Console.WriteLine("+: " + methods[0](operand1, operand2));
				break;
 			case '-':
				Console.WriteLine("-: " + methods[1](operand1, operand2));
 				break;
			case '*':
				Console.WriteLine("*: " + methods[2](operand1, operand2));
				break;
			case '/':
				Console.WriteLine("/: " + methods[3](operand1, operand2));
				break;
		}
	}
}

class Program
{

	delegate void WorkDelegate(char arg1, int arg2, int arg3);

	static void Main(string[] args)
	{
		Mathematics math = new Mathematics();
		WorkDelegate work = math.Calculate;

		work('+', 10, 5);
		work('-', 10, 5);
		work('*', 10, 5);
		work('/', 10, 5);
	}
}

 

예제 실행 화면

 

 

여러개의 메서드를 하나의 델리게이트로 가리키는 것도 가능하다. += 연산자를 이용해 메서드를 델리게이트 인스턴스에 추가하고 -= 연산자를 사용해 메서드 보관 목록에서 해당 메서드를 제거할 수 있다.

 

ex)

class Program
{
	delegate void CalcDelegate(int x, int y);

	static void Add(int x, int y) { Console.WriteLine(x + y); }
	static void Subtract(int x, int y) { Console.WriteLine(x - y); }
	static void Multiply(int x, int y) { Console.WriteLine(x * y); }
	static void Divide(int x, int y) { Console.WriteLine(x / y); }

	static void Main(string[] args)
	{
		CalcDelegate calc = Add;
		calc += Subtract;
		calc += Multiply;
		calc += Divide;

		calc(10, 5);
            
		Console.WriteLine();
		calc -= Multiply;
		calc(10, 5);
	}
}

 

예제 실행 화면

 

test)

다음 설명을 확인하고 내용을 반영하여 클래스 3개를 코드로 구현하시오.

  • 부모 클래스, 자식 클래스의 구조를 구현하시오.
  • 부모 클래스명은 Person으로 구현하시오.
  • 상속받는 클래스명은 Developer와 Sales로 구현하시오.
  • 부모 클래스의 필드 3가지를 이름(name), 나이(age), 부서(dept)로 하고 타입을 적절하게 선택하여 작성하시오.
  • 부모 클래스의 필드 3가지를 string형으로 리턴하는 ToString메서드를 오버라이드하여 작성하시오.
  • 부모 클래스에서 가상 메소드를 구현하여야 하며 "회사원 입니다."를 화면에 출력하는 기능을 부여하시오.
  • Developer 클래스는 부모 클래스를 상속받으며 가상 메소드를 재정의해서 "개발자 입니다."라고 화면에 출력하게 하시오.
  • Sales 클래스는 부모 클래스를 상속받으며 가상 메소드를 재정의해서 "세일즈맨 입니다."라고 화면에 출력하게 하시오.
  • Main() 메소드가 포함된 Program 클래스를 구현하시오.
  • Main() 메소드에는 Person 배열을 생성하고 2명의 신상 정보를 Developer, Sales 객체를 생성하며 입력하시오.
  • Main() 메소드의 Person 배열을 foreach문을 사용하여 객체 정보를 출력하고 가상 메서드를 호출하시오.

 

실행화면

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _2020_06_04_006
{
    public class Person
    {
        string name;
        int age;
        string dept;

        public Person(string name, int age, string dept)
        {
            this.name = name;
            this.age = age;
            this.dept = dept;
        }

        public override string ToString()
        {
            return "이름:" + name + "\n나이:" + age + "\n부서:" + dept;
        }

        public virtual void Print()
        {
            Console.WriteLine("회사원 입니다.");
        }
    }

    public class Developer : Person
    {
        public Developer(string name, int age, string dept) : base(name, age, dept)
        {

        }

        public override void Print()
        {
            Console.WriteLine("개발자 입니다.");
        }
    }

    public class Sales : Person
    {
        public Sales(string name, int age, string dept) : base(name, age, dept)
        {

        }
        public override void Print()
        {
            Console.WriteLine("세일즈맨 입니다.");
        }
    }


    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("과정명 : 스마트팩토리 과정");
            Console.WriteLine("교과목 : C# OOP/자료구조");
            Console.WriteLine("응시일 : 2020.06.04.");
            Console.WriteLine("응시자 : 김한진\n");
            Person[] p = new Person[] { new Developer("홍길동",27,"연구소"), new Sales("고길동",25,"판매") };


            foreach(Person temp in p)
            {
                Console.WriteLine(temp);
                temp.Print();
                Console.WriteLine("==========================");
            }
        }
    }
}

 

실행 화면

 

'스마트팩토리 > C#' 카테고리의 다른 글

14. 복습  (0) 2020.06.26
13. 복습  (0) 2020.06.25
11. 다형성  (0) 2020.06.03
10. Object, Array, this, base, 다형성  (0) 2020.06.02
9. 캡슐화, 정보 은닉, 프로퍼티, 상속, as, is  (0) 2020.06.01
COMMENT