Chapter07. 클래스
1. 객체지향 프로그래밍(OOP)와 클래스(class)
> C# 에서는 모든 것이 클래스로 이루어져 있음
> 클래스는 데이터(필드)와 메서드를 품을 수 있는 집합체이자, 하나의 데이터 형식이라고 볼 수 있음
int a;
// C에서는 int는 자료형, a는 변수
// C#에서는 int는 클래스이며 a는 객체
2. this()
> this()는 this가 객체 본인을 가르키는 키워드의 역할을 하는 것처럼 객체 본인의 생성자를 가르키는 역할을 함
class MyClass
{
int a, b;
public MyClass()
{
this.a = 5425;
}
// MyClass(int b) 생성자는 this()를 통해 MyClass()를 호출하여 a를 초기화(이니셜라이저)하고, 본문을 통해 b를 초기화함
public MyClass(int b) : this()
{
this.b = b;
}
}
3. base
> base는 상속 관계에서 기반 클래스를 가르킬 수 있는 키워드임
class First
{
public void FirstMethod() { }
}
class Second : First
{
public void SecondMethod()
{
base.FirstMethod(); // base 키워드로 기반 클래스의 메서드에 접근
}
}
3.1 base()
> base()는 상속 관계에서 기반 클래스의 생성자를 가르킬 수 있는 생성자임
class First
{
protected string Name;
public First(string Name)
{
this.Name = Name;
}
}
class Second : First
{
public Second(string Name) : base(Name) { } // base() 생성자로 기반 클래스의 생성자에 접근
}
4. is
> is는 객체를 원하는 형식과 비교하여 결과를 bool로 반환함
// 클래스 정의
class Mammal
{
public void Nurse() {}
}
class Dog : Mammal
{
public void Bark() {}
}
Mammal mammal = new Dog();
Dog dog;
// mammal 객체가 Dog 형식인지 검사 후 맞다면 True를, 아니라면 False로 반환함
if (mammal is Dog) {
dog = (Dog)mammal;
dog.Bark();
}
4.1 as
> as는 형식 변환 연산자로써 객체를 원하는 형식으로 형 변환하되, 실패한 경우 참조 객체를 null 값으로 채움
class Mammal
{
public void Nurse() {}
}
class Cat : Mammal
{
public void Meow() {}
}
Mammal mammal = new Cat();
Cat cat = mammal as Cat; // mammal 객체를 Cat 형식으로 형 변환하되, 실패시에는 참조 객체인 cat을 null 값으로 채움
if (cat != null) {
cat.Meow();
}
5. 메서드 숨기기(new)
> 메서드 숨기기는 명시적으로 같은 이름의 기반 클래스의 메서드를 무시할 때 사용한다
> 하지만 오버라이딩과는 아예 다른 개념이기 때문에, 정적 바인딩인 경우(virtual, override를 사용하지 않는 경우를 말함) 컴파일 시점에서 생성된 객체의 타입이 기반 클래스인 경우에는 기반 클래스의 메서드가 사용되므로 주의해야 함
class Base
{
public void MyMethod() { }
}
class Derived : Base
{
public new void MyMethod() { } // new 키워드가 사용됨
}
// 파생 클래스 형식으로 생성된 객체
Derived derived = new Derived();
derived.MyMethod(); // 기반 클래스의 메서드를 무시한다
// 기반 클래스 형식으로 생성된 객체
Base base = new Derived();
Base.MyMethod(); // 정적 바인딩인 경우 base 객체의 형식을 기준으로 판단하므로 Base 클래스의 메서드가 사용됨
6. 오버라이딩 봉인(seald)
> 오버라이딩을 할 수 없도록 막아놓는 걸 말한다.
> 기반 클래스가 virtual 선언을 해놓은 것만을 대상으로 한다
> 기반 클래스 작성자의 virtual 선언 의도는 명백히 파생 클래스들의 오버라이딩인데, 1차 파생 클래스 작성자는 자신 이후의 오버라이딩을 원하지 않을 수 있으므로 선택을 할 수 있도록 만들어놓은 키워드라 할 수 있다.
class Base
{
public virtual void Seal(){ } // 오버라이딩 목적을 위한 virtual 선언
}
class Derived : Base
{
public sealed override Seal(){ } // 오버라이딩 후 sealed 키워드를 통해 이후의 오버라이딩 봉인
}
class Overrrid : Derived
{
public override void seal(){ } // 오버라이딩 금지되었음에도 시도하여 이 부분에서 컴파일 에러가 발생함
}
7. 읽기전용(readonly)
> const 키워드와 비슷처럼 한번 값을 지정 후 변경할 수 없는 것이 특징임
private readonly int num;
8. 확장 메서드
> 확장 메서드는 클래스 및 형식에 메서드를 추가하는 것을 의미함
namespace 네임스페이스
{
public static class 클래스 // static 키워드 필요함
{
public static 반환형식 메서드(this 형식 식별자, 매개변수) { // static 키워드 필요함
}
}
}
using System;
namespace Extension
{
public static class AppendExtension
{
// 확장 메서드 정의
public static string Append(this string str, string toAppend)
{
return str + toAppend;
}
}
}
> string이라는 클래스에 Append 라는 메서드를 사용자 정의로 추가할 수 있다.
9. 튜플
1) 명명되지 않은 튜플
var tuple = (123, 789); // var을 쓰는 이유는 컴파일러가 튜플을 알아서 해석할 수 있도록 하기 위함
> C# 컴파일러는 명명되지 않은 튜플을 저장할 때 item1 부터 인덱스를 붙여 순서대로 저장한다.
> item1 : 123, item2 : 789 가 되는 것
2) 명명된 튜플
var tuple = (firstNum : 123, secondNum : 789);
3) 분해
> 인수가 같아야 함
var tuple = (firstNum : 123, secondNum : 789);
var (thirdNum, fourthNum) = tuple;
> thirdNum : 123, fourthNum : 789 가 됨
Chapter08. 인터페이스와 추상 클래스
1. 인터페이스(Interface)
1) 인터페이스?
> 인터페이스는 다른 파생클래스들의 상속대상이 될 수 있으며, 다른 파생클래스들이 지켜야 할 약속들을 사전에 정의해놓고 파생클래스들이 재정의하도록 강제 시킨다.
> 여기서 지켜야 할 약속들은 인터페이스가 정의한 멤버를 반드시 구현해야 한다는 약속이다.
2) 기본사용
interface 인터페이스
{
메서드
메서드
...
}
interface ILogger
{
void WriteLog(string message);
}
▲ 위 처럼 정의할 수 있다.
ILogger logger = new ILogger() // (x)
ILogger logger = new ConsoleLogger(); // (o), ConsoleLogger은 ILogger 인터페이스를 상속하는 파생 클래스
▲ 위 처럼 인터페이스는 직접 객체를 생성할 수는 없지만 참조는 만들 수 있다.
3) 파생 클래스에서 사용
interface ILogger // 인터페이스 ILogger
{
void WriteLog(string message); // 사전에 정의한 WriteLog 메서드
}
class ConsoleLogger : ILogger // 인터페이스 ILogger를 상속하는 ConsoleLogger 클래스
{
// 인터페이스가 정의한 약속들을 구현할 의무가 있는 ConsoleLogger 클래스는 WirteLog 메서드를 목적에 맞게 정의한다.
public void WirteLog(string message)
{
Console.WriteLine("{0} {1}", DateTime.Now.ToLocalTime(), message);
}
}
class ClimateMonitor
{
// ClimateMonitor 클래스는 인터페이스인 ILogger형 객체를 가지고 초기화를 진행한다
private ILogger logger;
public ClimateMonitor(ILogger logger)
{
this.logger = logger;
}
public void start()
{
while(true)
{
Console.Write("온도를 입력하세요 : ");
string temperature = Console.ReadLine();
if(temperature == "") break;
logger.WriteLog("현재 온도 : " + temperature);
}
}
}
ClkimateMonitor monitor = new ClimateMonitor(new ConsoleLogger()); // ILogger logger = new ConsoleLogger()
monitor.start(); // start() 함수에서 logger.WriteLog는 ConsoleLogger 클래스 안의 WriteLog 메서드가 됨
4) 의문점
> 그냥 클래스에 정의하고 쓰면 되는 거 아닌가? 라는 의문점이 많이 들었다.
> 하지만 아래와 같은 사례로 인터페이스는 유용하다.
class ClimateMonitor{
private ConsoleLogger logger;
public ClimateMonitor(ConsoleLogger logger){
this.logger = logger;
}
}
▲ 위 처럼 정의하면 ClimateMonitor는 ConsoleLogger 형 객체만을 사용하는 단순한 클래스가 된다.
반면
class ClimateMonitor {
private ILogger logger;
public ClimateMonitor(ILogger logger) {
this.logger = logger;
}
}
▲ 위 처럼 정의하면 ClimateMonitor는 ConsoleLogger 형 뿐만 아니라 인터페이스를 상속하여 앞으로 확장할 수 있는 FileLogger, DbLogger 등 여러가지 형의 객체도 받아들일 수 있는 상태가 된다.
> 따라서 인터페이스는 원하는 동작을 약속해놓고, 이를 상속한 파생 클래스들의 목적에 따라 다른 로직으로 분기시키기 위해서 사용된다.
> 같은 이름의 메서드(=> WriteLog)지만 파생 클래스마다 다른 행동을 가지고 있는 메서드(=> ConsoleLogger의 WirteLog / FileLogger의 WriteLog)는 어떤 클래스로 초기화했느냐에 따라(=> ILogger logger = new ConsoleLogger / ILogger logger = new FileLogger) 전혀 다른 결과를 만들어내는 것이다.
> 이는 같은 WriteLog 호출이지만 실제 동작은 객체 종류에 따라 달라진다는 다형성을 충족시킨다.
2. 추상 클래스(abstract class)
1) 추상 클래스?
> 추상 클래스는 인터페이스처럼 약속을 정의하고, 상속하는 파생 클래스들에게 강제시킬 수 있음과 동시에 클래스와 유사한 특징(기본 private 선언)을 가지는 클래스이다.
> 인터페이스는 기본적으로 public 선언이 되는 것과 차이점이 있다.
> 하지만 기본적인 private 선언 때문에 파생 클래스들이 접근을 할 수 없다면 약속의 의미가 없으므로, C#에서는 public, proteced 등의 한정자 중 하나로 수식을 할 것을 강요한다.
2) 사용법
abstract class 클래스
{
// 필드
// 메서드
}
abstract class AbstractBase
{
public abstract void SomeMethod(); // 추상 클래스의 메서드도 abstract 한정자를 사용해야 함.
}
class Derived : AbstractBase // 추상 클래스 AbstractBase를 상속하는 Derived 파생 클래스
{
public override void SomeMethod(){} // 약속이 강제되어 SomeMethod 메서드를 오버라이드해서 재정의함.
}'LMS 7 > 개발일지' 카테고리의 다른 글
| 25.09.29 개발일지 / C# 2(3) (Chapter11, Chapter12) (0) | 2025.11.11 |
|---|---|
| 25.09.28 개발일지 / C# 2(2) (Chapter09, Chapter10) (0) | 2025.11.11 |
| 25.09.26 개발일지 / C# 1(1) (Chapter02~Chapter03) (0) | 2025.11.11 |
| 25.09.25 개발일지 (0) | 2025.11.04 |
| 25.09.24 개발일지 / Windows Git (0) | 2025.11.04 |