'클래스'에 해당되는 글 6건

  1. 2009.04.06 클래스에서의 함수 포인터 사용
  2. 2008.10.21 문자열 이야기
  3. 2007.12.25 FileSystem Class - 미완성
  4. 2007.11.06 [C++]String Class
  5. 2007.09.23 레퍼런스와 상속
  6. 2007.09.07 레퍼런스 변수 1
Study - Programming/C/C++2009. 4. 6. 19:28
  어제 _beginthreadex()함수를 호출하다가 이런일이 있었다. 예를 들면 대충 이러한 상황이였다.

class ex_Class  //예제 클래스
{
private:
  unsigned WINAPI ThreadProc(LPVOID lParam)  //스레드를 위한 함수
  {
    //코오드
  }
  void TestFunction();

}
  void ex_Class::TestFunction()
  {
    _beginthreadex(NULL,0,ThreadProc,...);//스레드 생성
  }


이러니 _beginthreadex부분에서 컴파일 에러가 났다.  이유는 ThreadProc가 올바르지 않는 호출이라고..
처음에는 왜 그런지 몰라서 한참 헤매다가 나중에 겨우 이유를 찾았다.(당시에 인터넷도 안되고 해서 로컬 MSDN으로 한참 고생했다.)


우선 ThreadProc는 &ex_Class:ThreadProc같은 형태로 인자를 넘겨야 한다. ex_Class의 멤버함수이므로 접근 한정자를 붙여 주고 포인터이므로 &를 붙여 준다.
다음으로ThreadProc는 static으로 설정해야 한다. 함수 포인터의 호출이기 때문에 어느 한 객체에 소속되지 않게 하기 위해서 static으로 선언해야 한다. 이때문에 함수 내에서 멤버의 접근을 하기 위해서는 다음과 같은 방식으로 접근하여야 한다.

static unsigned WINAPI ThreadProc(LPVOID lParam)
{
  ex_Class *cls = (ex_Class*)lParam;
  cls->(멤버) 접근;
}

이는 꼭 스레드호출만이 아니라 함수포인터와 관련된 부분에서 해야 하는 것이다. 이런 상황에서 이런 오류를 만나서 예시가 이렇게 되었을뿐, 다른 상황에서도 마찬가지이다.
으흠... 아직 배우고 공부해야 할게 많다.
Posted by 머리
Study - Programming/C/C++2008. 10. 21. 19:37
  요즘 '조엘 온 소프트웨어'라는 책을 읽고 있는데 그 책에서 문자열 관련 이야기가 나오기에 그 내용을 참고하여 한번 이야기 하고자 한다.

  C의 문자열 구조는 먼저 문자열 내용이 있고 그 다음 '널 문자'가 들어가는 형식이다. 즉 "Hello"라는 문자열을 표현하려면 

'H' 'e' 'l' 'l'o' '\0' (단,\0 은 Null Characher)

  이렇게 6글자(sizeof(char) == 1이므로 6Byte)를 차지하게 된다. 이 Null Character의 사용 용도는 문자열의 끝(End of String)을 나타내기 위한 방법인데, 적어도 C에서는 이 문자가 없다면 메모리 어느 부분에 우연히 이 문자가 있는 것을 발견할때까지 계속해서 읽게 되어 엉뚱한 문자열이 나오게 된다.

  언뜻 보면 무슨 내용이 들어 있을 지 모르는 메모리에 이런 방식으로 문자열을 담는 것은 꽤 괜찮은 방법처럼 보인다. 하지만 조금 만 더 생각해보면 이것보다 좋은 대안을 찾을 수 있다.
  무엇보다 위 방식의 가장 큰 단점은 무슨 작업을 하려면 반드시 문자열 처음부터 끝까지 탐색을 하러 가야 한다는 것이다.
  예를 들어보자. 문자열의 길이를 알아내는 함수(strlen)를 구현해 보자고 한다면 문자열의 첫 포인터에서 Null Character을 찾을 때까지 포인터를 이동시켜야 한다.
  그런데 만약에 이 문자열의 길이가 100이라면? 그리고 1000이라면? 이런식으로 가면 문자열이 길면 길수록 그 처리 속도는 길어질 것이다. 다른 예로, 두 문자열을 잇는 함수(strcat)를 구현하자고 하면 두 문자열의 길이를 알아서 한 문자열에 할당된 크기를 다시 합친 크기로 재할당 해야 하고 문자열의 끝으로 이동해서 복사하는 과정을 수행해야 한다. 이것 역시 문자열의 길이를 구하는 과정에서부터 속도의 문제가 발생한다.
  이런 것을 해결하기 위한 방법으로는 뭐가 있을까? 이런 방법이 있을 수 있다.

'5' 'H' 'e' 'l' 'l' 'o'

  즉, 문자열의 첫 바이트에 문자열의 길이를 넣는 것이다. 이러면 굳이 끝까지 가서 널 문자를 찾을 필요 없이 길이를 첫 바이트에서 알 수 있으므로 그 크기 만큼 포인터를 이동해서 해결 할 수 있다. 여기서 주의해야 할 점은 끝부분에 Null Character을 넣는 방식은 하지 말라는 것이다. 그렇게 하면 정말 이도 저도 아닌 형편없는 문자열 표현 방식이 된다.
  다른 방법으로는 String Class를 구현하는 것인데, 이미 객체지향 프로그래밍 언어나 좀더 고급언어인 경우에는 지원되는 경우가 많다. 클래스의 멤버로 다음과 같은 예를 들 수 있다.

1. 문자열의 저장할 변수
2. 문자열의 길이를 저장할 변수
3. 기타 문자열 관련 함수

  위 방법으로는 효과적이고 자기 나름대로의 알고리즘으로 효율적으로 문자열을 관리 할 수 있을 것이다. 그리고 나 같으면 문자열을 저장 할 때 더이상 Null Character은 넣지 않도록 구현 할 것이다. 그리고 C++같은 경우라면 Operator Overloading등의 기능을 통해서 출력 및 입력, 기타 연산등의 방법도 구현해 보겠다.다만 위의 방법은 각자의 클래스 구현으로 표준이 규정되어 있지 않다면 호환성에서 문제가 발생 할 수 있겠고 조금 무거울 것이다.

  이외에도 많은 방법이 있을 것이다. 중요한 것은 이런 기본 데이터 타입에 만족하지 않고, 뭔가 다른 방식을 조금씩 연구하고 구현해 본다면 많은 도움이 될 것이다.
Posted by 머리
Study - Programming/C#2007. 12. 25. 13:06

다음주에 작은아버지께 드릴 프로그램을 위해서 만들어 본 클래스이다.

백업 프로그램인데, 모든 파일을 경로와 파일명 그대로 다른 드라이브로 옮겨 주기 위해서 만들어 클래스들

그런데 이거 참 클래스 이름 짓기가 참 난감했다. 이걸 뭐라고 해줘야 하나..
그래서 그냥 어울리지는 않지만 FileSystem이라고 이름지엇다.

class FileSystem
{
    /*CopyAll : 특정 디렉토리의 모든 폴더와 파일을 다른 드라이브로 옮기는 메서드
     * args : 원본의 경로
     * drive : 옮길 드라이브
     */
    public void CopyAll(string args,string drive)
    {
        DirectoryInfo dinfo = new DirectoryInfo(args);
        string dest;
       
        if (dinfo.Exists)
        {
            DirectoryInfo[] dir = dinfo.GetDirectories();
           
            foreach (DirectoryInfo d in dir)
            {
                CopyAll(d.FullName,drive);
            }

            FileInfo []fs = dinfo.GetFiles();

            foreach (FileInfo f in fs)
            {
                dest = f.Directory.FullName;
                dest = dest.Remove(0, 1);
                dest = dest.Insert(0, drive);
                Console.WriteLine("Copy " + f.Name + " to " + dest);
                FileCopy(f.FullName, dest, 0);
            }
        }
    }
    /* MakeDir : 디렉토리를 만드는 메서드
     * dir : 만들 디렉토리의 경로
     */
    public void MakeDir(string dir)
    {
        DirectoryInfo dinfo = new DirectoryInfo(dir);

        if (dinfo.Exists == false)
        {
            dinfo.Create();
        }
    }


    /* FileCopy : 파일을 복사하는 함수
     * src : 복사할 파일의 경로 및 파일 이름
     * dest : 복사할 목적지
     * mode : 파일을 복사할것인지, 이동할것인지 설정
     */

    public void FileCopy(string src,string dest,int mode)
    {
        FileInfo finfo = new FileInfo(src);
        FileInfo fsrc;
        if (finfo.Exists == true)
        {
            MakeDir(dest);
            dest = dest + "\\" + finfo.Name;
            switch (mode)
            {
                case 0:
                      fsrc = finfo.CopyTo(dest, true);
                    break;
                case 1:
                    finfo.MoveTo(dest);
                    break;
            }
        }
    }  
}

Posted by 머리
Study - Programming/C/C++2007. 11. 6. 02:12

  Int Class에 이어 이번에 만들어 본 것은 String Class. C/C++에서의 문자열 처리를 보완하기 위하여 만들어 본 클래스이다. VB나 기타 다른 언어의 String형과 비슷하게 만들어 보았다.
구현한 것은 다음과 같다.

1. Constructors/Destructor
2. Adding Operator(+)
3. Equal Operator(==)
3. Assignment Operator(=)
4. Lenght Method
5. Standard IO Interface
  이렇게 나열하고 보니 몇가지 구현해보고 싶은게 많이 생기네.. Mid,Left,Right Method나 != Operator 같은것들.. 뭐 다음 기회로 미루자.

int Class 만들때보다 연산자 오버로딩을 좀 더 익숙하게 다룬 것 같다. 다음에 만들어 볼 것은 Matrix Class.

invalid-file

Class_String

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 머리