* 상속
class 기반 클래스
{...}
class 파생 클래스 : 기반 클래스
{...}
- 파생 클래스는 기반 클래스의 모든 것을 물려받는다. private만 빼고
- 생성시 기반 -> 파생 순서로 생성, 소멸은 파생 -> 기반 순서로 소멸
* 파생 클래스에서 기반 클래스의 변수 초기화
class Program2
{
public string name;
public Program2(string name)
{
this.name = name;
}
}
class Program : Program2
{
public Program(string name) : base(name)
{
Console.WriteLine(name);
}
static void Main(string[] args)
{
Program a = new Program("abc");
}
}
// 파생 클래스의 생성자 : base() 형식으로 기반 클래스의 생성자로 이동
// 기반 클래스부터 수행 후에 파생 클래스 수행
* 기반과 파생 클래스 사이의 형식 변환 그리고 is, as
class Cat : Mammal
{
public void Meow()
{
Console.WriteLine("Meow()");
}
}
class MainApp
{
static void Main(string[] args)
{
Mammal mammal = new Dog(); // 파생의인스턴스는기반인스턴스로쓸수있다. mammal 객체가dog 형식이다.
Dog dog;
if (mammal is Dog) // mammal 객체가dog 형식인가맞다네그럼bool에서true
{
dog = (Dog)mammal; // 형식변환. (int)a 처럼
dog.Bark();
}
Mammal mammal2 = new Cat();
Cat cat = mammal2 as Cat // 형식이맞다면cat에null이아닌값이들어감
if (cat != null)
cat.Meow();
Cat cat2 = mammal as Cat
if (cat2 != null)
cat2.Meow();
else
Console.WriteLine("cat2 is not a Cat");
}
}
- is 와 as는 (객체 is 클래스) 또는 (객체 as 클래스) 형태이다.
- is는 true와 false를 반환해서 if문에 쓰면 좋고 as는 null 또는 클래스를 반환함.
- 객체에 클래스가 제대로 들어갔는지 검사하는 용도로 쓰임.
* 기반과 파생 클래스 변환 방법
class Program2
{
public int a = 10;
public int b = 20;
public void c (int x)
{
Console.Write(x);
}
}
class Program : Program2
{
public int x = 11;
public int y = 22;
public void z(int zz)
{
Console.Write(zz);
}
static void Main(string[] args)
{
// 기반 <- 파생
Program2 a = new Program();
Console.WriteLine("{0} {1}", a.a, a.b);
// 파생 <- 기반
Program bb = (Program)a;
Console.WriteLine("{0} {1} {2} {3}", bb.a, bb.b, bb.x, bb.y);
}
}
- 객체 하나로 기반과 파생을 바꿔가면서 접근할 수 있다.
- 시작은 기반 <- 파생 형태이다. 기반클래스 객체 = new 파생클래스(); // 반대로 하면 안됨..
- 파생 <- 기반 바꿀 때는 파생클래스 객체 = (파생클래스)객체;
class Program3
{
public virtual void initial()
{
Console.WriteLine("aaa");
}
}
class Program2 : Program3
{
public override void initial()
{
base.initial();
Console.WriteLine("bbb");
}
}
class Program : Program3
{
public override void initial()
{
base.initial(); // 오버라이딩 된 곳에서 기반 접근할 때
Console.WriteLine("ccc");
}
static void Main(string[] args)
{
Program a = new Program();
a.initial();
}
}
// 기반 클래스에 메소드 하나를 추가함. virtual로 말이다.
// 파생 클래스에는 같은 이름의 메소드를 만들면서 override로 사용한다.
// 같은 이름의 메소드를 파생 클래스에서 사용할 수 있다.
// 기반 클래스에 바로 접근할 수 있는 base. 형태는 파생 클래스의 메소드 안에서 사용할 수 있다.
// private 형태는 상속 받을 수도 없고 오버라이딩 할 수 없다.
- 만약 program3 a = new program() 이라면 a.initial()는 파생에서 출력할까 기반에서 출력할까?
- program3 클래스이므로 당연히 기반에서 출력해야하지만 오버라이딩된 파생에서 출력함.
* new 한정자
class Base
{
public void MyMethod()
{
Console.WriteLine("a");
}
}
class Derived : Base
{
public new void MyMethod()
{
Console.WriteLine("b");
}
}
class MainApp
{
static void Main(string[] args)
{
Base baseObj = new Base();
baseObj.MyMethod(); // a
Derived derivedObj = new Derived();
derivedObj.MyMethod(); // b
Base baseOrDerived = new Derived();
baseOrDerived.MyMethod(); // override 되었다면 b겠지만.. new로 숨겨서 a가 됨.
}
}
- 한정자에 new가 들어가면 숨기게 된다.
- 각각 기반, 파생 클래스에 접근하는데는 무리없음.
- 거의 쓸모없음.
* 오버라이딩 봉인
class Base
{
public virtual void SealMe()
{
}
}
class Derived : Base
{
public sealed override void SealMe()
{
}
}
class WantToOverride : Derived
{
public override void SealMe()
{
}
}
class MainApp
{
static void Main(string[] args)
{
}
}
- new 한정자는 override를 빼고 new를 붙였다면 봉인은 sealed를 추가하여 붙임
- 오버라이딩 했지만 뭔가 컴파일 에러등으로 오버라이딩하고 싶지 않을 때 사용
- 여튼 별로 필요없음