|
## 클래스 문법
|
|
## 클래스 문법
|
|
|
|
---
|
|
|
|
|
|
|
|
### **클래스**
|
|
|
|
**클래스(Class)**에는 *Field*, *Method*, *생성자*, *소멸자*와 같은 *멤버(Member)*들을 포함할 수 있다. *Filed*는 클래스 내부에 선언된 속성으로 임의 형식의 변수를 말한다. 클래스의 멤버들을 선언할 때 접근 한정자(`private`, `protected`, `public`)를 생략하면 `private`으로 정의된다. 객체를 생성할 때는 **Reference Type**으로 할당되며, `new` 키워드를 사용한다. C#에서는 `delete`와 같은 키워드가 없어 의도적으로 할당 해제를 할 수 없다. 하지만 **Garbage Collector**에서 사용되고 있지 않는 객체를 할당 자동으로 해제하는 역할을 한다. 이때 *소멸자*가 호출되며 자동으로 해제되므로 그 시기를 알 수 없다. **클래스**에서 `this` 키워드를 사용하여 자신의 객체를 참조할 수 있다.
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
class Person
|
|
|
|
{
|
|
|
|
private string name; // Field
|
|
|
|
|
|
|
|
public Person() // 기본 생성자(매개변수가 없는 생성자)
|
|
|
|
{
|
|
|
|
this.name = "이름 없음";
|
|
|
|
}
|
|
|
|
|
|
|
|
public Person(string name) // 매개변수가 있는 생성자
|
|
|
|
{
|
|
|
|
this.name = name;
|
|
|
|
}
|
|
|
|
|
|
|
|
~Person() // 소멸자
|
|
|
|
{
|
|
|
|
// 자원 해제
|
|
|
|
}
|
|
|
|
|
|
|
|
public void printPersonInfo() // Method
|
|
|
|
{
|
|
|
|
Console.WriteLine("Name : " + name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
#### **클래스와 구조체 비교**
|
|
|
|
| **특징** | **클래스** | **구조체** |
|
|
|
|
| -------- | -------- | -------- |
|
|
|
|
| **형식** | **Reference Type** | **Value Type** |
|
|
|
|
| **할당** | `Object obj = new Object();` | `Object obj;` 또는 `Object obj = new Object();` |
|
|
|
|
| **기본 생성자 정의** | 가능 | 불가능 |
|
|
|
|
| **상속** | 가능 | 불가능 |
|
|
|
|
| **인터페이스** | 가능 | 가능 |
|
|
|
|
| **abstract** | 가능 | 가능 |
|
|
|
|
| **static** | 가능 | 불가능 |
|
|
|
|
|
|
|
|
#### **정적 멤버, 인스턴스 멤버**
|
|
|
|
* **인스턴스 멤버** : `new` 키워드를 사용해서 메모리에 할당된 객체의 멤버이다.
|
|
|
|
* **정적 멤버** : 객체를 생성하지 않고도 사용할 수 있는 멤버로 *정적 Filed*, *정적 Method*, *정적 생성자*가 있다. 즉, 객체 개별로 사용하는 게 아니라 전역으로 사용할 수 있다. 멤버의 선언 앞에 `static`을 사용하며, 객체가 처음 생성되거나 **정적 멤버**가 참조되기 전 자동으로 초기화 및 호출이 된다.
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
class Person
|
|
|
|
{
|
|
|
|
public static int id = 0; // 정적 Filed
|
|
|
|
public static int count; // 정적 Filed
|
|
|
|
|
|
|
|
static Person() // 정적 생성자
|
|
|
|
{
|
|
|
|
count = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void printICount() // 정적 Method
|
|
|
|
{
|
|
|
|
Console.WriteLine("Count : " + count);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
```javascript
|
|
|
|
Console.WriteLine(Person.id); // 출력 결과 : 0
|
|
|
|
Person.printICount(); // 출력 결과 : 0
|
|
|
|
```
|
|
|
|
|
|
|
|
#### **Namespace**
|
|
|
|
**Namespace**를 정의함으로써 수많은 클래스와 Method를 분류하여 쉽게 구분할 수 있도록 해준다. **.NET Framework**에서는 **Namespace**를 사용하여 **기본 클래스 라이브러리(Basic CLass Library, BCL)**를 분류해 놓았다.
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
namespace InputDvice
|
|
|
|
{
|
|
|
|
class Keyboard { }
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace OutputDvice
|
|
|
|
{
|
|
|
|
class Monitor { }
|
|
|
|
}
|
|
|
|
```
|
|
|
|
```javascript
|
|
|
|
InputDvice.Keyboard keyboard = new InputDvice.Keyboard();
|
|
|
|
OutputDvice.Monitor monitor = new OutputDvice.Monitor();
|
|
|
|
```
|
|
|
|
|
|
|
|
* `using` 키워드로 **Namespace**를 미리 선언하면 생략해서 사용할 수 있다.
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
using InputDvice;
|
|
|
|
using OutputDvice;
|
|
|
|
```
|
|
|
|
```javascript
|
|
|
|
Keyboard keyboard = new Keyboard();
|
|
|
|
Monitor monitor = new Monitor();
|
|
|
|
```
|
|
|
|
|
|
|
|
### **인터페이스**
|
|
|
|
**인터페이스(Interface)**는 세부적인 내용은 구현하지 않고, 객체가 기본적으로 가져야 할 공통적인 기능들만 정의한 것이다. 정의된 기능들은 객체에서 상속받으면 반드시 재정의해야 하고 그 안에서 세부적인 내용을 추가한다. **인터페이스**의 멤버로는 **Method**, **Property**, **Event**, **Indexer**을 사용할 수 있다.
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
interface IKeyboard
|
|
|
|
{
|
|
|
|
void pressed();
|
|
|
|
}
|
|
|
|
interface IMouse
|
|
|
|
{
|
|
|
|
void click();
|
|
|
|
}
|
|
|
|
class Computer : IKeyboard, IMouse
|
|
|
|
{
|
|
|
|
public pressed() { }
|
|
|
|
public click() { }
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
#### **인터페이스의 특징**
|
|
|
|
* 기본적으로 `public`과 `abstract`는 묵시적으로 적용된다.
|
|
|
|
* **인터페이스**를 상속받으면 자식 객체에서 구현할 때 반드시 `public`을 사용해야 한다.
|
|
|
|
* 접근 한정자(`private`, `protected`, `public`) 또는 `abstract`, `virtual`, `override`, `new` 등의 키워드를 사용할 수 없다.
|
|
|
|
* **클래스**는 다중 상속이 불가능하지만, **인터페이스**는 다중 상속을 허용된다.
|
|
|
|
|
|
|
|
### **상속**
|
|
|
|
**상속(Inheritance)**은 기존 클래스에서 이미 정의된 것들을 다른 클래스에서 사용하거나, 추가 또는 재정의할 수 있도록 한 것이다. 여기서 기존 클래스는 *기반(Based) 클래스*라고 하고, 상속받은 다른 클래스는 *파생(Derived) 클래스*라고 부른다. *파생 클래스*는 하나의 기반 클래스만 상속 받을 수 있으며, *파생 클래스*가 다른 클래스의 *기반 클래스*가 될 수도 있다. C#에서는 `Base` 키워드를 사용하여 *기반 클래스*의 생성자나 Method를 호출할 수 있다.
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
public class BaseClass
|
|
|
|
{
|
|
|
|
private string a;
|
|
|
|
|
|
|
|
public BaseClass(string a)
|
|
|
|
{
|
|
|
|
this.a = a;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public class DerivedClass : BaseClass
|
|
|
|
{
|
|
|
|
private int b;
|
|
|
|
|
|
|
|
public void DerivedClass(string a, int age) : base(a)
|
|
|
|
{
|
|
|
|
this.b = b;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
### **다형성**
|
|
|
|
**다형성(Polymorphism)**이란 객체는 여러 형태를 가질 수 있음을 의미한다. 클래스가 상속관계일 때 *Override*, *Overload*, *추상 클래스*, *인터페이스*, *Casting*와 같은 형태에서 **다형성**을 적용시킬 수 있다.
|
|
|
|
|
|
|
|
다형성은 같은 메시지에 다른 동작이 가능하게 하는 인데요
|
|
|
|
|
|
|
|
C#에서는 *Boxing*, *Unboxing*, *Delegate* 등 **다형성**에 대한 다양한 기능들을 제공한다.
|
|
|
|
형성의 실현은 자신으로부터 상속받아 만들어진 파생 클래스를 통해 이루어진다.
|
|
|
|
|
|
|
|
파생 클래스에 따라 다양하게 재정의
|
|
|
|
|
|
|
|
#### **Method Override**
|
|
|
|
**Method Override**는 *기반 클래스*에서 상속받은 *Method*를 *파생 클래스*에서 사용할 기능으로 재정의하는 것이다. *기반 클래스*의 Method에 `virtual` 키워드를 사용하면 *가상 Method*로 정의된다. *파생 클래스*에서 `override` 키워드를 사용하여 상속받은 Method를 재정의 하며, 반드시 *가상 Method*와 같은 형태로 정의해야 한다.
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
public class BaseClass
|
|
|
|
{
|
|
|
|
public virtual void printClassInfo()
|
|
|
|
{
|
|
|
|
Console.WriteLine("Base Class");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public class DerivedClass : BaseClass
|
|
|
|
{
|
|
|
|
public override void printClassInfo()
|
|
|
|
{
|
|
|
|
Console.WriteLine("Derived Class");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
```javascript
|
|
|
|
BaseClass b = new BaseClass();
|
|
|
|
BaseClass d = new DerivedClass();
|
|
|
|
|
|
|
|
b.printClassinfo(); // 출력 결과 : Base Class
|
|
|
|
d.printClassinfo(); // 출력 결과 : Derived Class
|
|
|
|
```
|
|
|
|
|
|
|
|
* *파생 클래스*에서 재정의할 목적이 없을 때 `override`를 사용하지 않으면 다음과 같은 *warning*이 나타난다. 이때 *가상 Method*를 재정의하지 않으려면 `new` 키워드를 사용하면 된다.
|
|
|
|
|
|
|
|
> 현재 멤버가 해당 구현을 재정의하도록 하려면 override 키워드를 추가하십시오. 그렇지 않으면 new 키워드를 추가하십시오.
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
public class DerivedClass : BaseClass
|
|
|
|
{
|
|
|
|
public new void printClassInfo()
|
|
|
|
{
|
|
|
|
Console.WriteLine("Derived Class");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
* **Property**로 정의 된 Method도 재정의를 할 수 있다.
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
class Item
|
|
|
|
{
|
|
|
|
private int _price;
|
|
|
|
public virtual int price
|
|
|
|
{
|
|
|
|
get { return _price; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public class UsedItem : Item
|
|
|
|
{
|
|
|
|
public override int price
|
|
|
|
{
|
|
|
|
get { return price * 0.5; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
* .Net Framework의 모든 클래스는 Object라는 기본 클래스를 상속받는다. Object에 기본적으로 포함되어 있는 Method도 Override를 할 수 있다.
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
class MyClass
|
|
|
|
{
|
|
|
|
public override string ToString() // Object.ToString() Override
|
|
|
|
{
|
|
|
|
return "My Class";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
#### **Method Overload**
|
|
|
|
* **Method Overload**는 이름만 같은 Method가 매개변수의 개수와 형식만 다르게 다중 정의(Overloading)하는 것이다.
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
class Mathematics
|
|
|
|
{
|
|
|
|
public int Add(int value)
|
|
|
|
{
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
public int Add(int value1, int value2)
|
|
|
|
{
|
|
|
|
return value1 + value2;
|
|
|
|
}
|
|
|
|
|
|
|
|
public double Add(double value1, double value2)
|
|
|
|
{
|
|
|
|
return value1 + value2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
* **연산자 Overload**
|
|
|
|
**연산자 Overload**는 *정적 Method*에 `+`, `-`, `*`, `/` 등과 같은 연산자를 `operator` 키워드를 사용해 다중 정의(Overloading)하는 것이다.
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
class Adder
|
|
|
|
{
|
|
|
|
public int value;
|
|
|
|
|
|
|
|
public Adder(int value)
|
|
|
|
{
|
|
|
|
this.value = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static Adder operator +(Adder op1, Adder op2)
|
|
|
|
{
|
|
|
|
return new Adder(op1.value + op2.value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
```javascript
|
|
|
|
Adder number1 = new Adder(3);
|
|
|
|
Adder number2 = new Adder(2);
|
|
|
|
|
|
|
|
Adder result = number1 + number2;
|
|
|
|
|
|
|
|
Console.WriteLine(result.value); // 출력 결과 : 5
|
|
|
|
```
|
|
|
|
|
|
|
|
#### 추상 클래스
|
|
|
|
|
|
|
|
|
|
|
|
#### Casting
|
|
|
|
|
|
|
|
|
|
|
|
### **Property**
|
|
|
|
**클래스**에서 *Field* 값을 읽고 쓰기 위해 *접근자 Method*를 사용한다. 하지만 *Field*를 생성할 때마다 일일이 정의해야 하고, 코드가 길어져 가독성이 떨어진다. **Property**를 사용하여 이를 단순화 시킬 수 있다.
|
|
|
|
|
|
|
|
* `get`과 `set` 접근자를 사용하여 **Property**를 사용할 수 있다. `set` 접근자에는 매개변수 대신에 `value` 키워드를 사용한다.
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
class Person
|
|
|
|
{
|
|
|
|
private string _name;
|
|
|
|
public string name
|
|
|
|
{
|
|
|
|
get { return _name; }
|
|
|
|
set { _name; = value; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
```javascript
|
|
|
|
Person person;
|
|
|
|
person.age = "김선욱";
|
|
|
|
Console.WriteLine(person.name); // 출력 결과 : 김선욱
|
|
|
|
```
|
|
|
|
|
|
|
|
* C# 3.0부터는 자동구현 **Property**를 제공하여 더 간결하게 정의할 수 있다.
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
class Person
|
|
|
|
{
|
|
|
|
public string name { name; private name; } // 접근 한정자 사용 가능
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
### **Partial**
|
|
|
|
#### **Partial Type**
|
|
|
|
**Partial Type**는 **클래스**, **구조체** 또는 **인터페이스**의 정의를 여러 개로 나누는 것이다. **Partial Type**을 정의할 때는 `partial` 키워드를 사용하며, 여러 파일로도 나누어 정의할 수도 있다.
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
// Project.model.cs
|
|
|
|
partial class Project
|
|
|
|
{
|
|
|
|
public void Model();
|
|
|
|
}
|
|
|
|
```
|
|
|
|
```javascript
|
|
|
|
// Project.view.cs
|
|
|
|
partial class Project
|
|
|
|
{
|
|
|
|
public void View();
|
|
|
|
}
|
|
|
|
```
|
|
|
|
```javascript
|
|
|
|
// Project.controller.cs
|
|
|
|
public partial class Project
|
|
|
|
{
|
|
|
|
public void Controller();
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
#### **Partial Mothod**
|
|
|
|
**Partial Method**는 **Partial Type**의 Method를 나누어 정의하는 것이다. Method를 *선언*과 *본문*으로 나누며 `void`로 반환해야 한다. 접근 한정자를 사용할 수 없지만, 암묵적으로 `private`로 선언된다.
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
partial class Project
|
|
|
|
{
|
|
|
|
partial void printProjectInfo(string name);
|
|
|
|
}
|
|
|
|
|
|
|
|
public partial class Project
|
|
|
|
{
|
|
|
|
partial void printProjectInfo(string name)
|
|
|
|
{
|
|
|
|
Console.WriteLine("Project : " + name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
``` |
|
|
|
\ No newline at end of file |