C#의 클래스 문법은 C++과 닮았고
C++과 비슷한 자바와도 닮아있습니다.
큰 의미는 없는데 좀 더 비교를 하면
자바쪽과 더 비슷한 것 같습니다.
C#은 CLR 가상머신 개념 등 자바를
카피했다는 이야기가 나오는 것도
무리는 아니지요. 어차피 언어는
다 비슷한 부분이 있고 MS가 C#을
돈을 받고 파는 제품은 아니니까
너무 심각하게 생각할 필요는 없을듯 합니다.
다만 문법을 배울 때는 언어간의 유사성이나
차이점도 알아둘 필요는 있습니다.
클래스는 다음과 같이 선언합니다.
(선언 - declaration - 이라고도 하고
정의 - definition - 라고도 합니다)
class MyClass
{
}
클래스의 중요한 멤버 두개가 있습니다.
하나는 멤버 변수인 필드, 또 하나는
멤버 함수인 메소드입니다.
추가하면 아래와 같습니다. C++은
private: public: 처럼 접근제어자로
구분하는데 C#은 자바의 문법처럼
개별 멤버에 private과 public
키워드를 지정합니다.
class MyClass
{
private int myVar;
public void showMyVar()
{
Console.WriteLine(myVar);
}
}
여기에 property(속성) 이 하나 더 있는데
그건 private 필드를 관리하는 하나의
방식이니까 처음에는 헷갈릴 수가 있습니다.
핵심인 필드와 메소드라는 개념부터 잡습니다.
(다른 객체지향 프로그래밍 언어에서도 같다)
필드는 클래스가 사용하는 데이터 타입을
정의합니다. 메소드는 이 클래스에서
실행하는 코드입니다. C의 절차형 프로그램과
다른 것은 전역 변수를 여러 함수에서
사용할 일이 없다는 것 입니다.
객체의 수명에 따라 필드와
메소드의 수명이 결정됩니다.
클래스는 일종의 타입이고 틀입니다.
타입을 정의했으니 그것을 실제 런타임에
메모리에서 실행시켜야 합니다.
메모리에 생성된 실체를 인스턴스라고 합니다.
(혹은 객체도 같은 말이다)
인스턴스를 생성하고 메소드를 호출하는 법은
아래와 같습니다. 아래 코드에서 m1 은
클래스 참조 변수입니다. m1 에 실제 값이
저장되어 있는게 아니라 참조(reference),
즉 메모리 주소를 가지고 있습니다.
using System;
namespace CodingGak
{
class Program
{
static void Main()
{
MyClass m1;
m1 = new MyClass();
m1.showMyVar();
}
}
class MyClass
{
private int _var1 = 10;
public void showMyVar()
{
Console.WriteLine(this._var1);
}
}
}
MyClass m1;
-> MyClass 타입을 가리키는 참조 변수 선언
스택에 저장된다.
m1 = new MyClass();
-> MyClass 객체를 동적 메모리에 할당하고
그 참조 변수를 m1에 대입한다.
m1.showMyVar();
-> m1 인스턴스의 메소드를 호출한다.
*new 연산자는 C언어의 malloc 업그레이드
형태입니다. 클래스에서는 new 를 사용합니다.
malloc 은 메모리를 할당하는 함수입니다.
new는 메모리 할당과 생성자 호출 등
객체지향 프로그래밍 기능들을
수행하는 연산자입니다.
쉽게 말해 malloc 함수보다 더 많은
일을 편리하게 처리해 줘서
프로그래머는 거의 신경을 안써도 됩니다.
이 참조와 인스턴스 개념은 초보자가
익숙해지는데 시간이 걸립니다.
C언어의 포인터를 이해한다면
상당히 쉽게 이해할 수 있는 내용이...
아쉽게도 많은 사람들이 C언어에서
포인터 부분에서 많이 그만둔 것 처럼
그 개념을 모르면 이해에 한계가 있습니다.
참조(reference)라는 용어는 직접적으로
그 값을 가진 것이 아니라는 뜻 입니다.
참조 변수를 만들면 메모리 저장공간이
두개가 필요합니다. 하나는 목적지가
정해진 참조변수를 위한 공간이고
다른 하나는 실제 값이 저장되어 있습니다.
하나의 객체를 사용하는데 두개의
메모리를 사용하다니? 공간 낭비가
아닐까 의심이 듭니다.
조금 더 깊이 파고들기 위해서
어셈블리어까지 이야기할 때도 있지만
최대한 간단하게 설명하면...
현대의 프로그램의 런타임에서는
스택과 힙 메모리 관리를 중요시합니다.
정적 타이핑(static typing)이나 동적 타이핑
(dynamic typing)은 컴파일타임과 런타임의
특성과 밀접한 관련이 있습니다.
C# 에서 Main 함수에 선언하는 지역변수나
런타임에 코드들은 스택에서 실행됩니다.
비주얼 스튜디오같이 표준적인 IDE에서
보통 스택의 메모리 할당은 1Mega 로
설정되어 있습니다. 스택 메모리는 말하자면
소스코드를 컴파일 할 때 이미 확정된
데이터를 주로 넣는 공간입니다.
다시 말해 여러번 실행해도 바뀔 가능성이
없는 데이터를 넣는 목적입니다.
스택 메모리는 최대한 작고 효율적으로
유지하니까 성능이 좋습니다.
반면 클래스의 인스턴스는 힙 메모리에
생성하는데 힙메모리의 특징은 기가 단위로
넓은 메모리를 사용할 수 있는 장점이 있지만,
예측이 잘 안되기 때문에 성능상 최적화가
스택에 비해서 잘 되지 않습니다.
예를 들어 사용자에게 문자열을 입력을 받는
메소드가 있습니다. 이것은 컴파일 타임에
예측이 불가능합니다. 런타임에 이루어지는 거라서
한 문장을 입력받을 수도 있지만
극단적으로 한권의 책을 입력받을 수도 있습니다.
이런 데이터를 처리하려면 용량이 작고
효율성을 따지기 보다는 좀 느리더라도
용량이 큰 힙 메모리를 사용하는게 적합합니다.
C언에서 힙메모리를 할당할 때는 프로그래머가
malloc 함수로 자료형(바이트의 수)과 길이까지
입력 받아서 정확하게 메모리를 계산했지만
C#에서는 new 키워드로 퉁을 칩니다.
컴파일 타임에 알 수 없으니 CLR에서
알아서 계산하고 판단하게 하는 것입니다.
객체도... 용량에 차이가 있습니다.
예를 들어 String 객체를 몇개 입력 받는 것은
별로 부담이 안됩니다. "Hello World!"를 해봤자
아스키 코드로는 12 byte 유니코드로는 24 byte로
해결될 문제입니다. 그런데 고성능 카메라로 촬영한
10메가의 이미지 파일을 입력받는다면 어떨까요?
스택메모리로는 감당할 수 없습니다.
힙 메모리는 컴퓨터에 RAM을 꽂은 만큼
사용할 수 있습니다. (상주하는 운영체제 제외)
동영상 편집 프로그램 등 메모리를 많이 사용하는
프로그램이 느려지는 것은 힙메모리 점유율이
높아져서 입니다. (모자라면 하드드라이브를 페이지한다)
이렇게 태생적으로 객체는 스택에 놓고
사용할 수가 없습니다. 인스턴스를 new 키워드로
생성하는 것은 객체지향 프로그래밍의 설계방식입니다.
참고로 C++에서는 객체도 스택에서
생성할 수 있는데 C#이나 자바 같은
가상 머신을 사용하는 언어에서는
그것이 원체 불가능합니다.
그럼 스택은 무엇을 하느냐?
스택에 참조 변수(reference variable)을
놓고 힙 메모리를 컨트롤 하는 것 입니다.
MyClass m1; 에서 m1 은 클래스 참조 변수입니다.
그래서 클래스를 참조 타입이라고 합니다.
m1 = new MyClass(); 에서 m1은 MyClass의
인스턴스를 컨트롤 할 수 있는 참조 변수입니다/
참고로 예전에 Win32 에서는 인스턴스 핸들이라는
상당히 어려운 개념을 내놓기도 했는데
지금 시대에 와서 보면 너무나 당연하
개념을 최대한 어렵게 이름붙인 케이스입니다.
이런 부분들이 영어권 컴퓨터 너드(Nerd)들에게는
통용되었을지 모르지만 한국에서는
이해하기 어려웠던 기억이 납니다.
객체지향 프로그래밍에서 프로그래머는
클래스를 만들고 그 클래스로 인스턴스를 생성하여
참조 변수로 잘 사용하면 되는 것 입니다.
메모리의 원리를 모르면 용어에 휘둘리게 되있습니다.
해서 이 인스턴스가 무엇인가? 설명하는 것도 힘들고
이해하는 것도 참 힘든데, 여기서 적성이 안맞아서
소프트웨어 전공하다가 그만둔 케이스도 많은 만큼
좀 진지하게 프로그래밍을 하려는 사람들은
주의해야할 부분인 것은 맞습니다.
호기심이 많은 사람들은 C#과 자바의 설명이
불충분할 수도 있습니다. 가상머신이 있는
언어들에서는 좀 그런 면이 있습니다.
어떤 언어를 공부하더라도 원리를 추적하면
나오는 문제이긴 한데요. 좀 더 알고 싶다면
C와 C++을 공부해야 합니다. 거기서 더 나아가면
어셈블리어까지...
(이래서는 1990년대와 다를바가 없는 것 같지만)
약간 모르겠습니다. 응용 프로그래머가 목표라면
알 필요가 없긴 합니다만, 21세기 프로그래머라면
C++정도는 알아야 하지 않겠나 - 개인적인 의견입니다.
편견과 고정관념은 무섭습니다. 때로는
쓸때없는 논쟁에 목숨까지 걸기도 하지요.
다만 C# 교재에서 인스턴스를 설명하는게
충분한가? 응용 프로그래머에게 충분할 수 있고
또 만족 못하는 사람이 있을 수 있습니다.
설명을 하다 보니 아쉬움이 있습니다.
*******
코딩을 좀 해봤다면 C#의 문법을
배우는데는 그리 오래 걸리지 않을 거라 봅니다.
C#은 쉽게 사용할 수 있도록 만든
프로그래밍 언어입니다. 또 .NET 플랫폼의
중요한 구성요소로 자바 언어와 JVM의
관계와 비슷하지요. 단지 본질을 이해하는 것은
시간이 걸리는 일입니다. 그건 프로그래밍이
아니라 어떤 세상 일도 같다고 봅니다.
프로그래밍은 타이핑을 ㅈㄴ 하는 과정이지만
원리를 알아갈 수록 타이핑도 줄어들고
더 많은 일을 할 수 있습니다.
학습 초기에는 타이핑도 중요하지만
나중에는 디버그와 평가하는 시간이 많을 것입니다.
원리를 강조하는 것은 원리적은 것은
디버그와 평가에서 주요합니다.
자칫 잘못하면 맨땅에 헤딩 노가다가
될 수 있으니까 코드를 어느 정도
할 수 있게 되었다면 그 다음에는
이제 원리에 좀 집중해야 합니다.
인스턴스와 참조 그냥 하나의 챕터지만
대충 아는게 아니라 잘 알아야 좀 좋습니다.
(Best는 C++을 추천하지만 그것은
참으로 먼 길이긴 합니다)