객체가 생성될 때 생성자가 호출되고 소멸할 때는 종료자가 호출된다.
상위 클래스에서 선언된 메소드를 하위 클래스에서 재정의 하는 것이다.
상위 클래스에서 오버라이딩할 메서드를 미리 virtual로 한정한다.
하위 클래스는 virtual메서드를 override 한정자를 이용하여 재선언한다.
class Animal
{
protected string name;
public Animal(string name) { this.name = name; }
public virtual string GetName() { return name; }
}
class Dog : Animal
{
public Dog(string name) : base(name) { }
public override string GetName() { return $"강아지 이름: {name}"; } // 수정
}
class Cat : Animal
{
public Cat(string name) : base(name) { }
public override string GetName() { return $"고양이 이름: {name}"; } // 수정
}
is
as
Mammal mammal = new Dog();
Dog dog;
if(mammal is dog)
{
dog=(Dog)mammal;
dog.Bark();
}
Mammal mammal2 = new Cat();
Cat cat = mammal2 as Cat;
if(cat != null)
{
cat.Meow();
}
파생 클래스(혹은 자식 클래스)에서 기본 클래스(혹은 부모 클래스)의 생성자, 필드, 메서드를 접근해야 하는 경우 base 키워드를 사용하여 접근할 수 있다.
base 키워드는 메서드, 프로퍼티, 생성자 내에서만 사용할 수 있으며, static으로 선언된 정적 메서드에서는 사용할 수 없습니다. base 키워드는 기본 클래스와 파생 클래스에 동일한 이름의 필드가 존재하는 경우 유용하게 사용할 수 있다.
class ParentClass
{
public string strValue = "Hello";
public void ParentMethod()
{
Console.WriteLine("부모 클래스의 ParentMethod() 메서드 호출");
}
}
class ChildClass : ParentClass
{
public void ChildMethod()
{
Console.WriteLine("자식 클래스의 ChildMethod() 메서드 호출");
Console.WriteLine("부모 클래스의 strValue 필드의 값: " + base.strValue);
base.ParentMethod();
}
}
class Program
{
static void Main(string[] args)
{
ChildClass childObj = new ChildClass();
childObj.ChildMethod();
}
}
자식 클래스의 ChildMethod() 메서드 호출
부모 클래스의 strValue 필드의 값: Hello
부모 클래스의 ParentMethod() 메서드 호출
자식 클래스의 생성자 뒤에 콜론(:)과 base()를 사용하여 부모 클래스의 생성자를 호출할 수 있으며, 부모 클래스의 생성자 오버로딩이 존재하는 경우 base()에 매개변수를 전달할 수 있다.
class ParentClass
{
public ParentClass()
{
Console.WriteLine("ParentClass 클래스의 생성자");
}
public ParentClass(string strValue)
{
Console.WriteLine("ParentClass 클래스의 생성자");
Console.WriteLine("strValue의 값: " + strValue);
}
}
class ChildClass : ParentClass
{
public ChildClass() : base()
{
Console.WriteLine("ChildClass 클래스의 생성자");
}
public ChildClass(string strValue) : base(strValue)
{
}
}
class Program
{
static void Main(string[] args)
{
ChildClass childObj1 = new ChildClass();
ChildClass childObj2 = new ChildClass("Hello");
}
}
ParentClass 클래스의 생성자
ChildClass 클래스의 생성자
ParentClass 클래스의 생성자
strValue의 값: Hello
상속을 금지하는 sealed키워드
이 클래스는 다른 클래스에서 상속받을 수 없으며 이 클래스를 파생 클래스로도 사용할 수 없다.
sealed class MyClass
{
//
}
class MyBaseClass
{
public virtual void MyMethod() {}
}
class MyDerivedClass : MyBaseClass
{
public sealed override void MyMethod() {}
}
MyMethod 함수는 MyDerivedClass에서 오버라이딩되고 이후 sealed로 선언된다. 따라서 MyDerivedClass를 상속하는 다른 파생 클래스에서 MyMethod를 오버라이딩할 수 없게 된다.
virtual로 선언된 가상 메소드를 오버라이딩한 버전의 메소드만 가능하다.
일반적으로 클래스를 마지막으로 봉할 때 사용하는 키워드로 최종적인 구현을 제공하는 클래스에서 사용된다.
파생되어 추가되는 내용이 필요하지 않게 하거나 해당 기능을 변경하거나 확장하려는 경우를 방지해 클래스의 안정성을 보장한다.
예를 들어 C#의 String 클래스의 경우 sealed로 선언되어 있어 개발자가 해당 클래스를 상속하거나 수정할 수 없도록 만들어 클래스의 안정성을 보장하도록 한다.
const와 readonly의 차이
const 는 무조건 선언과 동시에 초기화 해야하고 값을 변경할 수 없다.
readonly 는 const 와 달리 런타임 상수 입니다. 즉, "프로그램이 실행중에 초기화 하는것도 가능한" 상수 입니다.언제 초기화를 할 수 있냐면, 클래스 생성자에서만 값을 변경(초기화) 해 줄 수 있다.
const 로 선언한 상수는 정적 변수(static 변수)와 동일하게 취급되기 때문에 "클래스.상수"로 접근이 가능하다.하지만 readonly 로 선언한 상수는 "인스턴스.상수"로 접근해야한다.
중첩 클래스는 클래스 내부에서 클래스를 정의한 것을 말한다.
클래스 구조를 그룹화하고 싶은 경우 중첩 클래스를 사용한다.
내부 클래스는 외부 클래스의 구조이므로 클래스 구조를 쉽게 파악할 수 있다.
내부 클래스에서 외부 클래스 멤버를 접근할 수 있다.
특정 클래스 내부에서만 사용되기 때문에 코드를 더 쉽게 파악할 수 있으며, 유지 관리가 쉽다.
특정 클래스 내부에서만 사용되므로 클래스 구조가 단순해진다.
업캐스팅은 서브 클래스의 인스턴스를 슈퍼 클래스 타입으로 변환하는 과정이다. 이 변환은 항상 안전하며 자동으로 이루어진다. 업캐스팅을 사용하면 서브 클래스 객체를 슈퍼 클래스의 참조로 사용할 수 있으며, 슈퍼 클래스에서 정의된 메서드에 접근할 수 있다.
다운캐스팅은 업캐스팅의 반대 과정으로, 슈퍼 클래스 타입의 객체를 서브 클래스 타입으로 변환하는 것을 말한다. 다운캐스팅은 명시적으로 형 변환 연산자를 사용해야 하며, 변환하려는 타입이 실제 객체의 타입과 호환되지 않으면 런타임 오류가 발생할 수 있다.
타입 호환성 검사: 다운캐스팅하기 전에, is 연산자나 as 연산자를 사용해 변환 가능성을 확인해야 한다.
런타임 오류의 위험: 타입 호환성이 없는 경우, 명시적 변환 시 런타임 오류가 발생할 수 있다.
생성자 오버로딩을 이용하여 매개변수를 다르게 할 수 있다.
public class MyClass
{
public
{
// 기본 생성자
}
public MyClass(int number)
{
// 정수 매개변수가 있는 생성자
}
public MyClass(string message)
{
// 문자열 매개변수가 있는 생성자
}
}
this 키워드를 사용하여 클래스의 현재 인스턴스에 접근할 수 있으며, 다른 생성자를 호출하는 데에도 사용할 수 있다.
static 키워드를 사용한다. 정적 생성자는 클래스에 대해 단 한번만 호출되며, 클래스의 정적 멤버를 초기화하는데 사용된다. 정적 생성자는 매개변수를 가질 수 없으며, 접근 제한자도 가질 수 없다.
참고
생성자 오버로딩 개념