C# 3
* 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
}
}