C#

C# 3

ryancha9 2019. 12. 9. 02:05

* C#에서의 클래스 구성요소 명칭


객체 = 인스턴스

클래스의 변수 = 필드

클래스의 함수 = 메소드

클래스의 멤버 = 변수, 함수



* 클래스는 값 형식인가? 참조 형식인가?


class abc{

public string aaa;

...

}


abc a = new abc();


- 객체 a에 메모리 할당 하는 것이 아니라 참조형식으로 a는 객체가 있는 곳을 가리킨다.



* 생성자


class abc{

public abc(){  // 생성자

...

}}


// 사용시 abc a = new abc();


class abc{


public int a;

public int b;


public abc(int a, int b){  // 생성자

this.a = a;

this.b = b;

}}


// 사용시 abc a = new abc(10, 20);


- 생성자를 사용하는 이유는 내가 원하는 멤버들을 초기화하기 위해

- 생성자는 한정자 (o) 리턴형 (x)



* 소멸자


- 소멸자는 사용하지말자. 가비지 컬렉터가 알아서 수거해간다.



* 인스턴스 메소드, 정적 메소드


- 클래스 내부의 메소드(함수)인데 static이 붙어있으면 인스턴스 없이 접근 가능한 정적 메소드

- static이 없으면 인스턴스가 있어야 접근이 가능한 메소드



* 깊은 복사, 얕은 복사


classA abc = new classA(); 

abc.a = 10;

abc.b = 20;

 

ClassA bbc = abc; 

bbc.b = 30;


// 이때 abc.b는 20, bbc.b는 30일까? 답은 abc.b bbc.b 둘 다 30이 됨


        스택             큐

abc [abc의 주소] -> [abc]  // abc는 스택에 abc의 주소를 가지고 10,20 값을 가진 클래스를 가리키고 있다.


bbc [abc의 주소] -> [abc]  // bbc는 스택에 abc의 주소를 가지고 10,20 값을 가진 클래스를 가리키고 있다.



- C#의 클래스는 참조 형식이기 때문에 기본적으로 얕은 복사이다. 깊은 복사 방법은 따로 구현해야한다.



// 깊은 복사 예제


class class1

{

public int a;

public int b;

 

public class1 c() // 새로운 클래스 만들어서 return 해줌

{

class1 ccc = new class1();

ccc.a = this.a; // 기존의 abc.a 값을 ccc 클래스에 넣는다.

ccc.b = this.b; // this는 classA의 인스턴스 abc 를 뜻함.

return ccc;

}

}

class Program

{

static void Main(string[] args)

{

class1 abc = new class1();

 

abc.a = 10;

abc.b = 20;

 

class1 bbc = abc.c(); // 돌려준 return 클래스를 bbc가 받아서 출력

bbc.b = 30;

Console.WriteLine("{0} {1} {2} {3}", abc.a, abc.b, bbc.a, bbc.b);

}

}


// abc의 메소드에서 새로운 클래스를 생성해서 변수들을 채워주고 리턴해서 출력하는 형식이다.



* this 키워드


class Employee

{

private string Name;

private string Position;

 

public void SetName(string Name)

{

this.Name = Name; 

}


// this.name과 그냥 name의 차이는 this는 자기 자신 클래스를 가리킨다.

// this.name은 employee 클래스의 필드 name이고 name은 파라미터로 넘어온 값이다.



* this 생성자 + 오버로딩


namespace ThisConstructor

{

class MyClass

{

int a, b, c;

 

public MyClass()

{

this.a = 5425;

Console.WriteLine("MyClass()");

}

 

public MyClass(int b): this()

{

this.b = b;

Console.WriteLine("MyClass({0})", a);

}

 

public MyClass(int b, int c): this(b)

{

this.c = c;

Console.WriteLine("MyClass({0}. {1})", b, c);

}

 

public void PrintFields()

{

Console.WriteLine("a:{0}, b:{1}, c:{2}", a, b, c);

}

}

 

class MainApp

{

static void Main(string[] args)

{

MyClass a = new MyClass();  // 빈 생성자 public MyClass()로 이동

a.PrintFields();  // 5425 출력

 

MyClass b = new MyClass(1);  // public MyClass(int b): this() -> public MyClass() -> public MyClass(int b): this()

b.PrintFields();  // 5425, 1 출력

 

MyClass c = new MyClass(10, 20);  // MyClass(int b, int c): this(b) -> MyClass(int b): this() -> public MyClass() -> 다시 내려옴

c.PrintFields();  // 5425, 10, 20 출력

}}}



// this 생성자를 통해 다른 생성자로 이동 가능하다.

// 생성자를 오버로딩했다.



* 접근 한정자


public - 클래스 외부 o 내부 o

protected - 클래스 외부 o 내부 o 파생 클래스에서 접근 o 

private - 클래스 외부 x 내부 o 파생 클래스에서 접근 x


// 멤버변수 선언시 한정자를 아무것도 지정하지 않으면 private로 됨 

// public과 proeteced는 자식에게 물려주지만 private는 물려주지 않음


  class Program

    {

        private int a;

        protected int b;

        public int c;

        public void ccc(int a)

        {

            this.a = a;

            Console.Write(this.a);

        }

    }

    class MainApp

    {

        static void Main(string[] args)

        {

            Program bbc = new Program();

            bbc.ccc(10); // 이렇게 내부 함수 통한 접근 가능하지만

            bbc.a = 10; // 외부에서 직접적인 접근 x

            bbc.b = 10; // 외부에서 직접적인 접근 x

            bbc.c = 20;  // 외부에서 직접적인 접근 o

        }

    }