C#/이것이 C#이다

7장. 클래스: this 키워드, this() 생성자, 접근 한정자, static 변수, 구조체

개발자엄지희 2023. 4. 19. 01:03
반응형
주의) 생성자나 종료자 개념 등 기본적인 것들은 생략하였습니다.

클래스가 뭐야? 


클래스란 int, string과 같이 하나의 형식이라고 생각하면 된다.

인스턴스는 클래스라는 붕어빵 틀로 찍어낸 각각의 붕어빵이라고 생각하면 쉽다.


생성자


class Cat
{
	// 생성자 자동 생성
}
생성자를 따로 명시하지 않을 경우 기본적으로 생성된다.

정적 필드와 메소드 선언, static


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestConsoleApp_4._19
{
    class Cat
    {
        public static int Speed = 10;
        public string Name = "";
        int _leg = 4;

        public Cat()
        { 
        	this.Speed += 10;
            // Speed += 10; // 과 동일, this 생략 가능
        }
        
        public Cat(string name) : this() // Cat() 호출
        {
        	this.Nmae = name;
        }
    }
    // 이하생략
}
지역 변수는 보통 변수명 앞에 _(언더바)를 붙임

this 키워드

클래스에서 함수 정의 시 필드(내부 변수)에 this 키워드는 생략 가능합니다.

this() 생성자

this() 생성자는 자기 자신의 생성자를 가리킵니다.

예제에서 MyCat()은 Speed를 올리고,
MyCat(string)은 Name을 설정합니다.
Speed를 올리는 것은 MyCat()을 호출하여 처리했습니다.

this()는 생성자에서만 사용할 수 있습니다.

https://qzqz.tistory.com/119

 

C# 클래스 6 - this 키워드, this() 생성자

this 키워드 this는 객체가 자신을 지칭할 때 사용하는 키워드입니다. 클래스 내부에서 필드명과, 메서드의 매개 변수의 이름이 동일할 때this 키워드로 모호성을 제거할 수 있습니다.this가 붙은 변

qzqz.tistory.com


접근 한정자란?


public 설명생략 internal 같은 어셈블리 언어 내에서의 public
protected 설명생략 protected internal 같은 어셈블리 언어 내에서의 protected
private 설명생략 private protected 같은 어셈블리 언어 내에서의,
상속받은 클래스 내부에서만 접근 가능
sealed: 오버라이딩 봉인
분할 클래스: 클래스의 구현이 길어질 경우 여러 파일에 나눠서 구현 (소스코드 관리의 편의 제공에 그침)

부모 객체에 접근하는 키워드, Base


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestConsoleApp_4._19
{
    class Animal
    {
        public string Name;
        public string Color;
        protected int Age;

        public Animal(string Name, string Color)
        {
            this.Name = Name;
            this.Color = Color;
        }

        protected void Sing()
        {
            Console.WriteLine("Sing~");
        }
    }

    class Cat : Animal
    {
        public static int Speed = 10;

        public Cat(): base("", "") { }

        public Cat(string Name, string Color): base(Name, Color) { }

        public Cat(string Name, string Color, int Age): base(Name, Color)
        {
            this.Age = Age;
        }

        ~Cat()
        {
            Console.WriteLine($"${this.Name}: 종료...");
        }// 종료자 - 사용하지 않는 것이 좋음
    }

    // 생략
}

 

Base 키워드를 통해 부모 클래스에 접근할 수 있습니다.
base()는 기반 클래스의 생성자입니다.

https://slaner.tistory.com/124

 

base 키워드를 알아보자

안녕하세요!정말 오랜만의 글입니다! 이 글에서는 C#의 base 키워드에 대해서 알아보려고 합니다. base 키워드해당 키워드를 사용하는 클래스의 부모 클래스를 가리키는 것일단, 코드를 보시겠습

slaner.tistory.com


기반 클래스 <=> 파생 클래스, is와 as 키워드


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestConsoleApp_4._19
{
    class Animal
    {
        public string Name;
        public string Color;
        protected int Age;

        public Animal(string Name, string Color)
        {
            this.Name = Name;
            this.Color = Color;
        }

        protected void Sing()
        {
            Console.WriteLine("Sing~");
        }
    }

    class Cat : Animal
    {
        public static int Speed = 10;

        public Cat(): base("", "") { }

        public Cat(string Name, string Color): base(Name, Color) { }

        public Cat(string Name, string Color, int Age): base(Name, Color)
        {
            this.Age = Age;
        }

        ~Cat()
        {
            Console.WriteLine($"${this.Name}: 종료...");
        }// 종료자 - 사용하지 않는 것이 좋음


        public void Meow()
        {
            Console.WriteLine($"{this.Name}: 야옹");
            base.Sing();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Animal animal = new Cat();

            if (animal is Cat) { // is: 해당 형식에 해당하는지 여부 반환
                Cat cat7 = animal as Cat; // as: 참조 형식에 대하여 형변환하며, 실패하는 경우 null 반환
                cat7.Meow();
            }
        }
    }
}

 

is 키워드: 해당 형식에 해당하는지의 여부(bool) 반환

as 키워드: 참조 형식에 대하여 형 변환, 실패 시 null 반환

animal(Cat의 인스턴스)이 Cat에 해당하면,
Animal에 담긴 animal을 Cat으로 형 변환 (다운캐스팅)

업캐스팅과 다운캐스팅

https://bonjenny.tistory.com/16

 

[C#] 업캐스팅과 다운캐스팅

https://see-ro-e.tistory.com/133 [C# 때려잡기] C# 강의 30. 다형성, 다운 캐스팅 업 캐스팅 기존에 내 캐릭터에 칼을 가지도록 하였다. class Weapon { public void Attack() { Console.WriteLine("무기로 공격!"); } } class Kni

bonjenny.tistory.com


static이란?


여러 개의 인스턴스가 하나의 부모 클래스 static 변수를 공유하고 있는 것이다.

예를 들자면 인스턴스의  같은 것이다.

static 변수가 아닌 인스턴스 변수는 인스턴스의 이름 같은 것이다.

// static O
class Person {
	static string 성 = "엄";
}
Person1 = new Person() {
	Person.성 = "김";
} // 모든 Person의 인스턴스의 성이 "김"으로 바뀜
Person2 = new Person() {
	Person.성 = "박";
} // 모든 Person의 인스턴스의 성이 "박"으로 바뀜 


// static X
class Person {
	string 성 = "엄";
}
Person1 = new Person() {
	Person1.성 = "김";
} // Person1 인스턴스의 성이 "김"으로 바뀜
Person2 = new Person() {
	Person2.성 = "박";
} // Person2 인스턴스의 성이 "박"으로 바뀜
정확하지 않은 문법이니 참고용으로만 봐주세요.

오버라이드와 다형성

class Animal
{
    public string Name;
    public string Color;
    protected int Age;

    public Animal(string Name, string Color)
    {
        this.Name = Name;
        this.Color = Color;
    }

    public virtual void Sing()
    {
        Console.WriteLine("Sing~");
    }
}

class Cat : Animal
{
    public static int Speed = 10;

    public Cat(): base("", "") { }

    public Cat(string Name, string Color): base(Name, Color) { }

    public Cat(string Name, string Color, int Age): base(Name, Color)
    {
        this.Age = Age;
    }


    public void Meow()
    {
        Console.WriteLine($"{this.Name}: 야옹");
        base.Sing();
    }

    public override void Sing()
    {
        Console.WriteLine("Cat Sing~");
    }
}

다형성(Polyorphism)이란?

다형성: 객체가 여러 형태를 가질 수 있음을 의미
즉, 자신으로부터 상속받아 만들어진 파생 클래스를 통해 다형성을 실현

Animal 클래스의 Sing 메소드를 업그레이드한 Cat 클래스의 Sing 메소드

오버라이딩을 위한 조건, virtual 키워드

virtual 키워드: 오버라이딩을 할 메소드가 virtual 키워드로 한정되어있어야 함

오버라이딩 정의, override 키워드

override 키워드: 재정의한 메소드 앞에 붙임, 메소드를 재정의하고있음을 컴파일러에게 알리는 역할


메소드 숨기기, sealed 키워드


sealed class Animal { } // 상속 불가

 

sealed 키워드: 해당 클래스의 상속을 불가하도록 만듭니다.

오버라이딩한 메소드는 파생 클래스의 파생 클래스에서도 자동으로 오버라이딩이 가능하므로, 브레이크를 걸어주기 위해 sealed 메소드가 필요한 것!

new 키워드로 메소드 숨기기? 오버라이드랑 다를게 뭐야?


class Animal
{
    public string Name;
    public string Color;
    protected int Age;

    public Animal(string Name, string Color)
    {
        this.Name = Name;
        this.Color = Color;
    }

    public virtual void Sing()
    {
        Console.WriteLine("Sing~");
    }

    public void Sing2()
    {
        Console.WriteLine("Sing2~");
    }
}

class Cat : Animal
{
    public static int Speed = 10;

    public Cat(): base("", "") { }

    public override void Sing()
    {
        Console.WriteLine("Cat Sing~");
    }

    public new void Sing2()
    {
        Console.WriteLine("Cat Sing2~");
    }
}

호출은 다음과 같이 할 수 있다.

Cat cat = new Cat();
cat.Sing2(); // Cat Sing2~ 출력

그러나 오버라이딩과 다른 점은, 다음과 같이 객체를 선언하면 Animal 버전의 Sing2() 메소드가 그대로 노출된다는 것이다.

Animal cat = new cat();
cat.Sing2(); // Sing2~ 출력
따라서 메소드 숨기기는 완전한 다형성을 구현하는 방법이 아니다. new보다는 override를 이용하자.

오버라이딩 봉인, sealed override


class Animal
{
    public string Name;
    public string Color;
    protected int Age;

    public Animal(string Name, string Color)
    {
        this.Name = Name;
        this.Color = Color;
    }

    public virtual void Sing()
    {
        Console.WriteLine("Sing~");
    }
}

class Cat : Animal
{
    public static int Speed = 10;

    public Cat(): base("", "") { }

    public sealed override void Sing()
    {
        Console.WriteLine("Cat Sing~");
    }
}

class KoreanCat: Cat
{
    //public override void Sing() // Error: 오버라이딩 불가
    //{
    //    Console.WriteLine("Cat Sing~");
    //}
}
virtual 로 선언된 Animal 클래스의 Sing() 메소드를 Cat 클래스가 오버라이드하여 구현하였다.
그러나 이후로 sealed override로 막아놓았기 때문에 KoreanCat 클래스에서는 오버라이딩이 불가하다.
Animal 클래스에서는 virtual 키워드로 이미 추상화가 가능하다고 선언해놓았기 때문에, 오버라이딩을 막는 키워드가 존재하지 않아도 괜찮다.

중첩 클래스와 분할 클래스


분할 클래스

단순히 개발의 편의성을 위해 여러 번에 나눠서 구현하는 클래스

중첩 클래스

Home home;
public void MakeHome()
{
    this.home = new Home();
}

public void Rest()
{
    this.home?.Cure(this);
}

class Home
{
    public void Cure(Cat cat)
    {
        cat.Age -= 1;
    }
}
중첩클래스는 자신이 소속되어있는 클래스의 멤버 (private 멤버에까지도!) 에 자유롭게 접근할 수 있다.

중첩 클래스를 사용하는 이유

1. 클래스 외부에 공개하고 싶지 않은 형식을 만들고자 할 때

2. 현재의 클래스 일부분처럼 표현할 수 있는 클래스를 만들고자 할 때


확장 메서드


확장 메서드: 기존 클래스의 기능을 확장하는 기법

static class CatExtension
{
    public static void Hug(this Cat cat)
    {
        Console.WriteLine($"{cat.Name}이 안아 줍니다.");
    }
}
이렇게 선언하면 Hug가 마치 본래 Cat의 메소드였던것처럼 사용할 수 있습니다.

클래스와 구조체


\ 클래스 구조체
키워드 class struct
형식 참조형식 값형식
복사 얕은 복사 깊은 복사
인스턴스 생성 new 연산자, 생성자 선언
생성자 매개변수 없는 생성자 선언 가능 매개변수 없는 생성자 선언 불가능
상속 가능 모든 구조체는 Object를 상속받는
ValueType을 상속받음

사용한 코드

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestConsoleApp_4._19
{
    class Animal
    {
        public string Name;
        public string Color;
        protected int Age;

        public Animal(string Name, string Color)
        {
            this.Name = Name;
            this.Color = Color;
        }

        public virtual void Sing()
        {
            Console.WriteLine("Sing~");
        }

        public void Sing2()
        {
            Console.WriteLine("Sing2~");
        }
    }

    class Cat : Animal
    {
        public static int Speed = 10;

        public Cat(): base("", "") { }

        public Cat(string Name, string Color): base(Name, Color) { }

        public Cat(string Name, string Color, int Age): base(Name, Color)
        {
            this.Age = Age;
        }

        ~Cat()
        {
            Console.WriteLine($"${this.Name}: 종료...");
        }// 종료자 - 사용하지 않는 것이 좋음


        public void Meow()
        {
            Console.WriteLine($"{this.Name}: 야옹");
            base.Sing();
        }

        public sealed override void Sing()
        {
            Console.WriteLine("Cat Sing~");
        }

        public new void Sing2()
        {
            Console.WriteLine("Cat Sing2~");
        }

        public void Run()
        {
            Console.WriteLine($"{this.Name}가 뜁니다 (속도: {Speed})");
        }

        public void SpeedUp()
        {
            Speed += 10;
        }

        static public void Play(Cat catA, Cat catB)
        {
            Console.WriteLine($"{catA.Name}와 {catB.Name}가 함께 놉니다.");
        }

        public Cat clone()
        {
            return new Cat(this.Name, this.Color);
        }

        public void setAge(int Age)
        {
            this.Age = Age;
        }

        public int getAge()
        {
            return this.Age;
        }


        // 중첩 클래스

        Home home;
        public void MakeHome()
        {
            this.home = new Home();
        }

        public void Rest()
        {
            this.home?.Cure(this);
        }

        class Home
        {
            public void Cure(Cat cat)
            {
                cat.Age -= 1;
            }
        }
    }

    class KoreanCat: Cat
    {
        //public override void Sing() // Error: 오버라이딩 불가
        //{
        //    Console.WriteLine("Cat Sing~");
        //}
    }

    static class CatExtension
    {
        public static void Hug(this Cat cat)
        {
            Console.WriteLine($"{cat.Name}이 안아 줍니다.");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Cat cat = new Cat();
            cat.Name = "키티";
            cat.Meow();

            // 참조형은 null 할당 가능
            cat = null;


            Cat cat1 = new Cat();
            cat1.Meow();

            Cat cat2 = new Cat("키티", "흰색");
            cat2.Meow();
            cat2.Hug();
            cat2.Run();
            cat2.SpeedUp();

            Cat cat3 = new Cat("나비", "검정");
            cat3.Run();
            Cat.Play(cat1, cat2);

            Cat cat4 = cat2; // 얕은 복사
            Cat cat5 = cat2.clone(); // 깊은 복사
            cat4.Meow();
            cat5.Meow();

            Cat cat6 = new Cat("키티", "흰색", 2);
            cat6.setAge(3);
            Console.WriteLine(cat6.getAge()); // cat6.Age 접근 불가

            // 중첩 클래스
            cat6.MakeHome();
            Console.WriteLine($"나이: {cat6.getAge()}");
            cat6.Rest();
            Console.WriteLine($"나이: {cat6.getAge()}");


            Animal animal = new Cat();

            if (animal is Cat) { // is: 해당 형식에 해당하는지 여부 반환
                Cat cat7 = animal as Cat; // as: 참조 형식에 대하여 형변환하며, 실패하는 경우 null 반환
                cat7.Meow();
            }

            cat2.Sing(); // Cat Sing~
            cat2.Sing2(); // Cat Sing2~

            Animal animal1 = cat2;
            animal1.Sing(); // Cat Sing~
            animal1.Sing2(); // Sing2~

            Console.ReadLine();
        }
    }
}
반응형