'레퍼런스'에 해당되는 글 4건

  1. 2008.10.24 동적 할당 이야기 - 3 1
  2. 2007.11.02 값의 비교와 레퍼런스
  3. 2007.09.23 레퍼런스와 상속
  4. 2007.09.07 레퍼런스 변수 1
Study- MSC/Computer2008. 10. 24. 19:48
  이번 포스팅에서는 동적할당을 객체의 생성쪽으로 확장해 보고자 한다. 먼저 말해두지만 이 포스팅은 포인터나 객체, 클래스를 설명하기 위한 포스팅이 아니다. 어디까지나 이런 사항에 대한 기본적인 지식은 알고 있다고 가정하고 진행하겠다. 우선 C++에서 Example이라는 클래스가 있고, 그것에 대한 객체를 생성해 보자.

Example ex;

  자. ex라는 객체가 생성되었다. 아마 특별한 문제 없이 제대로 돌아갈 것이다. 그리고 파괴도 잘 될 것이다. 하지만 이런 방식의 객체 생성은 권하고 싶지 않다. 대신 이런 객체의 생성을 권한다.

Example* pEx = new Example();

  위 방식은  Example라는 클래스 형식으로 메모리 공간에 할당을 한 후 그 주소를 pEx 포인터 변수에 넣어서 사용하게 하는 방식이다. 앞선 포스팅에서, 메모리의 어딘가에(HEAP) 공간을 할당한다고 했는데 위 방식도 바로 이런 방식이다. 이렇게 해 놓으면 이어서 이렇게도 가능하다

Example *pEx = new Example();
pEx = new Example();

  잘 이해가 가지 않을것이다. 무슨 이야기냐면 한 객체를 메모리에 생성하여 한 포인터에 주소를 기억시켰는데, 그 포인터를 재사용하여 또다른 객체를 또 생성하여 그 주소를 넣을 수 있다는 이야기이다. 물론 위 코드는 첫 객체의 해제에서 문제가 발생하지만 이런식으로 좀 더 코드에 유연성을 줄 수 있다. 그렇지 않으면 Example ex1,ex2; 등의 방식으로 객체를 생성해야 하는 문제가 발생한다.
  앞서 말한 유연성 외에도 이런 방식의 동적 할당을 통한 객체 생성은 맨 처음 말한 동적할당의 장점을 최대한 살릴 수가 있게 된다. 객체는 일반 변수보다 여기 저기서 사용될 가능성이 많다. 무슨 말이냐면 지역 변수 이상의 용도로 사용될 가능성이 많다는 이야기이다. 만약에 게임을 만들때 적을 표현하는 클래스가 있고 그 객체를 생성한다고 하면 상황에 따라 계속해서 적을 만들어 내야 하므로 동적 할당이 필요 할 수 밖에 없다.(int형으로 적을 표현할수는 없지 않은가?)
  이제까지는 객체를 동적할당 할 때 포인터를 이용하였다. 그 이유는 C++은 기본적으로 Call by Value 방식이기 때문이기 때문인데 이는 변수 및 객체의 사용을 한정적인 위치에서만 사용할 수 밖에 없게 만든다. 이 틀을 극복하기 위해서 메모리상의 주소로 읽기 위한 포인터가 사용되는데, 여기서 한단계 더 나가서 레퍼런스라는 개념이 나온다. 적어도 여기서는 Call by Reference와 Call by Address의 개념을 다르게 두자. Call by Address는 결론적으로는 포인터의 값을 이용한 Call by Value로 볼 수 있다. 엄밀하게 말하면 Call by Reference와는 다르다.(물론 내부적으로 이놈도 포인터를 쓰긴 쓴다.)
  말이 샜는데, C++ 이후의 객체 지향 언어는 기본 참조 방식을 Call by Value가 아니라 Call by Reference를 채택한 경우가 많다. JAVA가 그렇고, C#이 그러며, 심지어 Visual Basic도 Call by Reference가 기본이다.
  무슨 말이냐면 만약에

Example ex;

라는 코드가 있으면 C++에서는 ex가 객체 그 자체이지만 JAVA나 C#등에서는 저것은 그냥 참조를 위한 레퍼런스에 불과하지 객체 자체는 아니다. 즉 아무것도 못한다. 레퍼런스는 포인터처럼 메모리 상의 어떤 것을 가리켜야 그 의미가 있다. 즉

Example ex = new Example();

  와 같이 객체를 생성하고 그것을 참조하여야 한다.
  말이 많았다. 정작 하고 싶은 말은 '동적할당은 메모리 어딘가에 공간을 할당하고 포인터를 이용하여 그것을 참조한다, 그리고 이는 객체에서도 마찬가지이며 좀더 나아가 레퍼런스는 참조 없이는 아무런 의미가 없다'였는데 이것을 표현하기 위해 쓸데없는 말이 너무 많았던 것 같다.
  아무쪼록 이 글을 읽고 뭔가 '아!'하고 깨달음(?)을 얻는 프로그래머 지망생이 있으면 좋겠다. 그렇게 기원하면서 이상 3회에 걸친 포스팅을 마치고자 한다.
Posted by 머리
Study - Programming/JAVA2007. 11. 2. 01:42

  자바를 공부하면서 항상 느끼는 것인데.. 정말 자바는 객체로 시작해서 객체로 끝난다.. 이렇게 객체만 사용하다 보면 객체에 대한 감을 못잡을 리가 없다.

  다음 코드를 보자.

public class Equivalence {
 public static void main(String[] args)
 {
  Integer n1 = new Integer(10);
  Integer n2 = new Integer(10);
  System.out.println(n1==n2);
 }
}
  이 코드의 결과값은 무엇일까? 언뜻 보면 true일 것 같지만 답은 false이다. 왜 그럴까? 조금만 생각해보면 알 것이다. 위에서의 비교문은 n1이 가리키고 있는 객체와 n2가 가리키고 있는 객체가 같은 객체인가를 묻는 것이다. 그러니 당연히 false가 나올 수밖에.

  그렇다면 n1과 n2의 값을 비교하려면 어떻게 해야 할까? 답은 equals()메소드에 있다. n1==n2를 다음과 같이 고치면 true가 나올 수 있다.

n1.equals(n2)

  의미는 금방 파악이 갈 것이다. 값의 비교를 해 주는 메서드이다.

Posted by 머리
Study - Programming/C#2007. 9. 23. 22:18

다음 그림을 한번 보자.

사용자 삽입 이미지

위 그림의 코드를 보면 Chile 클래스는 Parent 클래스를 상속받아 있다. 그리고 Child는 Parent의 Show() 메서드를 오버라이드 했고, 추가로 Func()라는 메소드를 가지고 있다.

그럼 이젠 Main() 함수를 보자. 처음에는 Parent 형으로 obj라는 객체를 만들고 Parent 인스턴스를 만들어 참조했다.  물론 이 상태에서 Show를 하면 Parent의 Show()가 실행된다.
그럼 다음 줄로 넘어가 obj를 Child인스턴스에 참조시켜 보자. 물론 Show()메서드는 Child의 Show()가 실행된다. 그런데 그 다음줄로 넘어가 Func()를 실행시키려 시도해 보자. 일단 위 그림에서 자동완성의 목록에는 Func()가 없다. 그냥 무시하고 Func()를 타이핑해서 빌드 해 보자.
사용자 삽입 이미지
  위 그림을 보면 오류가 나온다. 간단히 테스트의 목적으로 만든 코드인데 한번 자세히 알아보자.

  우선 obj라는 객체는 Parent형으로 되어 있다. 즉 Parent의 틀을 가지고 있다는 것이다. 그러므로 obj = new Parent();로 해 놓으면 당연히 Parent의 모든 메서드를 사용하는 것이 가능하다.
  그러나 obj = new Child();로 해 놓으면 어떨까? obj의 '틀'은 Parent이다. 그런데 참조한 인스턴스는 Child이다. Child는 어떻게 되어 있는가? Parent를 상속받아 놓고 거기다 Show()를 오버라이드 한 다음 Child만의 Func()를 포함하고 있다. 즉 Parent라는 '틀'은 Child가 상속받고 있는 Parent관련 멤버들 및 오버라이드 함수만 레퍼런스 할 수 있고, Child만의 멤버인 Func는 사용할 수 없다는 이야기이다.
  솔직히 이게 무엇을 의미하는지 결론적으로는 잘 모르겠다. 다만 이런 식의 코드를 많이 보아 왔었는데 이게 어떻게 성립하는지 이해가 안되었다가 이해를 할 수 있게 되었다.
  폴리모피즘은 OOP에서도 어려운 개념이라고 들었다. 나도 다른 개념은 충분히 사용해 보면서 할 수 있겠는데 이 부분은 영 난해해서 힘들다. 공부를 더 해봐야 겠다.
Posted by 머리
Study - Programming/JAVA2007. 9. 7. 21:45
다음 코드가 있다.

int a;
a = 3;

  이렇게 하면 a의 값은 무엇일까? 당연히 1이다. 하지만 Test라는 클래스가 있고 이런 코드가 있다면 어떨까?

Test ex;

  ex는 아무것도 가리키고 있지 않다. Test형으로 변수를 만들었을 뿐이지만 이것은 아무 의미없는 객체라는 것이다. 단지 Test라는 형태의 틀만 가지고 있을뿐. 이럴 때 Test클래스 안에 Show라는 메소드가 있다고 치고, 다음과 같이 실행하면 에러가 발생한다.

ex.Show(); //에러

왜냐하면 ex는 아무것도 가리키고 있지 않기 때문이다. 이럴 떄는 새로운 인스턴스를 생성해 주어서 이 인스턴스를 가리키게 해 주어야 한다.

Test ex = new Test();

  잠깐 메모리 구조를 확인해보자.
  앞에서 int형 변수 a의 값은 바로 3이다. 그러나, ex의 값은 다르다. 메모리상으로 Test라는 클래스의 인스턴스가 하나 새로 생성되었고, ex는 이 인스턴스의 메모리 주소를 가리키고 있다. 즉 ex의 값은 인스턴스 자체는 아니라는 이야기다.

  ex와 같은 변수를 레퍼런스 변수라고 한다. C++의 레퍼런스와 상당히 비슷한 개념이다. 그렇다고 포인터는 아니다. 포인터는 주소에 직접 접근해서 그 값을 바꿀 수 있지만, 레퍼런스는 오로지 레퍼런스 변수를 통해서 그 안의 메소드와 멤버 변수만 사용할 수 있다.

  알아두자.일반 데이터형은 바로 그 값을 가리키지만 레퍼런스 변수는 그렇지 않다.
Posted by 머리