본문 바로가기

C# 공부/C# 기본 문법

클래스 - 2 (this(), 접근한정자, 상속, base키워드, is/as, 기반/파생 클래스간 형변환)

A. this( ) 생성자

class MyClass
{
	int a,b,c;
    
    public MyClass()
    {
    	this.a = 5425;
    }
    
    public MyClass(int b)
    {
    	this.a = 5425;
        this.b = b;
    }
    
    public MyClass(int b, int c)
    {
    	this.a = 5425;
        this.b = b;
        this.c = c;
    }
}

위 코드는 문제는 없지만 세 개의 MyClass( ) 생성자 안에 똑같은 코드가 중복되어 들어가있다.

이 문제를 this( ) 생성자를 이용해 해결가능하며 생성자에서 자기자신의 생성자를 가리킨다.

* this( ) 생성자를 사용할때는  생성자의 코드블록이 아닌 앞쪽에서만 사용이 가능하다. 

//this() 생성자를 적용시킨 코드
class MyClass
{
	int a,b,c;
    
    public MyClass()
    {
    	this.a = 5425;
    }
    
    public MyClass(int b) : this()
    {
    	this.b = b;
    }
    
    public MyClass(int b, int c) : this( b)
    {
    	this.c = c;
    }
}

 

B. 접근 한정자 (Access Modifier)

C#에서 제공하는 접근 한정자는 모두 여섯 가지이며, 아래와같다.

접근 한정자 설명
public 클래스의 내부/외부 모든 곳에서 접근할 수 있다.
protected 클래스의 외부에서는 접근할 수 없지만, 자식(파생) 클래스에서는 접근가능하다.
private 클래스의 내부에서만 접근할 수 있으며, 자식(파생) 클래스에서도 접근불가능하다.
internal 같은 어셈블리에 있는 코드에서만 public으로 접근할 수 있다. 다른 어셈블리에 있는 코드에서는 private과 같은 수준의 접근수준을 가진다.
protected internal 같은 어셈블리에 있는 코드에서만 protected로 접근할 수 있다. 다른 어셈블리에 있는 코드에서는 private과 같은 수준의 접근성을 가진다.
private protected 같은 어셈블리에 있는 클래스에서 상속받은 클래스 내부에서만 접근이 가능하다.

접근 한정자로 지정하지 않은 클래스 멤버는 private이 default로 지정된다.

 

+) 부모(기반) 클래스의 작성자는 의도하지  않은 상속 구현을 막기위해 sealed 한정자를 사용해서 상속이 불가능하도록 클래스 선언이 가능하다.

sealed class Base
{
	//..
}

class Derived : Base // --> 컴파일 에러
{
	//..
}

 

C. 클래스 상속 (파생 클래스-Derivced Clas 또는 자식 클래스)

파생 클래스의 이름 뒤에 콜론(:)을 붙이고 그 뒤에 상속받을 기반 클래스의 이름을 붙여주면된다.

class Base
{
	public void BaseMethod()
    {
    	Console.WriteLine("BaseMethod");
    }
}

Class Derived : Base
{
}

* 파생클래스의 객체를 생성할때는 기반(부모) 클래스의 생성자를 호출한후에 자신의 생성자를 호출하고, 

                    객체를 소멸할때는 자신의 종료자를 호출한후에 기반(부모) 클래스의 종료자를 호출한다.

 

1. base 키워드

기반클래스의 생성자가 매개 변수를 입력받도록 선언된경우, 파생클래스의 인스턴스를 생성할 때에 base키워드를 사용하면 기반클래스의 생성자에 매개변수를 전달할 수 있다.

class Base
{
	protected string Name;
    public Base(string Name)
    {
    	this.Name = Name;
    }
}

class Derived : Base
{
	public Derived(string Name) : base(Name)
    {
    	Console.WriteLine($"{this.Name}");
    }
}

' : base( ) ' 생성자 양식은 앞서나온 ' : this ( ) ' 생성자 양식과 동일하다.

base 키워드는 기반(부모) 클래스를 가리키고, this 키워드는 자기자신을 가리키는 차이뿐.

 

2. 기반 클래스와 파생 클래스 사이의 형식변환

C#은 기반클래스와 파생클래스 사이 족보를 오르내리는 형식변환이 가능하며, 파생클래스의 인스턴스는 기반클래스의 인스턴스로서도 사용할수있다. 

- 사용할때의 장점? 
포유류 클래스에서 300가지의 동물클래스가 파생되었을때,
사육사클래스에서 Wash()메소드 구현시 각각 구현하려면 300개의 메소드를 오버로딩으로 구현해야하지만,
300개의 동물클래스가 모두 Mammal 클래스로부터 상속받았기때문에 Mammal로 간주할수있다.
따라서, 다음과같이 딱하나의 Wash() 메소드만 준비하면 300개의동물클래스에 사용이 가능하다.

class Zookeeper
{
	public void Wash(Mammal mammal){/*---*/}
}

3. is와 as
C#은 형변환을 위해 연산자 두개를 제공한다.

연산자 설명
is 객체가 해당 형식에 해당하는지를 검사하여 그 결과를 bool 값으로 반환한다.
as 형식 변환 연산자와 같은 역할을 한다. 하지만 형번환 연산자가 반환에 실패하는 경우 예외를 던지는 반면 as 연산자는 객체 참조를 null로 만든다는 것이 다르다.
//is 연산자 사용예제
Mammal mammal = new Dog();
Dog dog;

if(mammal is Dog)
{
	dog = (Dog)mammal;  // mammal 객체가Dog 형식임을 확인했으므로 안전하게 형식변환이 이루어짐.
    dog.Bark();
}
//as연산자 사용예제
Mammal mammal2 = new Cat();
Cat cat = mammal2 as Cat;
if(cat!=null)
{
	cat.Meow(); //mammal2가 Cat 형식 변환에 실패했다면 cat은 null이 된다.
                //하지만 이코드에서는 mammal2가 Cat형식에 해당하므로 안전하게 형식변환이 이뤄진다.
}

* 일반적으로 형식 변환 연산자대신, as연산자를 사용하는쪽이 권장된다. (Bill Wagner의 Effective C# 참조)
-> 형식변환에 실패하더라도 예외가 일어나서 갑자기 코드가 점프하는일이 없으므로 코드관리에 수월하다.
     주의점은 as연산자는 참조형식에 대해서만 사용가능하므로 값형식의 객체는 기존 형식변환연산자를 사용해야한다.

★ 헷갈림 주의
자식객체가 부모객체로 형변환하는 업캐스팅은 가능,
부모객체가 자식객체로 형변환하는 다운캐스팅은 불가능하다.

부모에서 자식을 받는건되지만, 자식에서 부모를 받는것은 안된다로 기억

class Program
    {
        void ParentMethod()
        {
            Console.WriteLine("Parent객체의 메소드");
        }
    }

    class Csharp : Program
    {
        void testMethod() {
            Console.WriteLine("자식객체의 메소드");
        }
    }
    
    class MyClass
    {
        static void Main(string[] args)
        {
            Program pr = new Program(); 
            Program pr2 = new Program();

            Csharp cs = new Csharp();
            Csharp cs2 = new Csharp();

            cs = (Csharp)pr; //예외 발생 !!
            pr2 = (Program)cs2;// 정상
            
            Csharp cs3 = new Program(); //컴파일 오류!!
            Program pr3 = new Csharp(); //정상
        }
    }