2012년 2월 23일 목요일

[C++] 템플릿 (정리중)

템플릿은 헤더에 모든 코드가 들어있어야한다.
즉, 일반적인 파일분할처럼 .h와 .cpp로 정의와 구현이 구분되어 있으면 안된다는것.
그 이유는 컴파일시 inline함수처럼 코드복사가 일어나기 때문이다.


템플릿 코드를 컴파일해서 오브젝트 파일을 메모장으로 열어보면, 실제로는 TestClass<INT> 또는 TestFunc<FLOAT> 과 같은 이름으로 사용되고 있음을 볼 수 있다.




템플릿 함수 특수화 예시 코드

template <typename T>
void TestFunc(T& a)
{
      .....
}

template <>
void TestFunc(int& a)
{
      .....            ////  int 형에 대해서만 특수하게 적용할 코드를 작성한다.
}

[C++] 상속 (정리중)


자식에서 부모 상속시 헤더 파일에서 인클루드 한다. 이유는??


virtual 함수를 선언하면 클래스에 4바이트 공간이 생기고 그것을 상속클래스에서 관리한다.(함수 포인터 공간인듯) 이로 인해 함수 오버라이딩이 가능해진다.


생성자는 부모부터 실행된다. 초기화리스트(이니셜라이저)로 자식에서 부모 생성자를 호출할 수 있다.
소멸자는 자식부터 실행된다. 메모리 누수 등의 문제를 방지하기 위해서. 이 때문에 소멸자는 반드시 virtual 로 선언해야한다.


부모만이 자식을 품을 수 있다.
부모클래스 포인터로 자식객체를 가리킬 수 있다.(업캐스트)
자식클래스 포인터로 부모객체를 가리킬 수 없다.(다운캐스트: 부모클래스 포인터에서 자식포인터로 형변환)
단, 명시적 형변환은 가능.


상태패턴에 사용된다.

[C++][자료구조] 링크드 리스트(Linked List)

개념 같은건 책을 보면 나와있으니 구현시 실질적으로 중요한 것만 정리.


단일이든 양방향이든 리스트의 처음과 끝에 Head와 Tail 노드를 만든다(포인터가 아니라 실제 공간을 할당받은 노드).
이 두 노드는 데이터를 가지지 않고 처음과 끝을 가리키는 역할만 한다.
(구현시에는 리스트 클래스의 생성자와 소멸자에서 두 노드를 할당, 반환한다.)

이렇게 구현하였을때의 장점은 삽입/삭제 등 함수 내부에서 if 문으로 조건 체크를 해줘야할 빈도수가 현저히 줄어들어 구현이 훨씬 간단해 진다는 점.
사용시에도 조건체크를 하지 않으므로 실행 속도가 빠르다는 점.
단점은 두 개의 공간을 낭비한다는 것 뿐이다.


이것이야말로 일반 대학교재용 자료구조책에서는 절대 찾아 볼 수 없는 실용적인 방법론이라 말하지 아니하지 않을 수 없지 아니하지 않을 수 없는것이다ㅡ,.ㅡ






그리고 이건 햄스터의 슬픔(...응??)



[C++] 문자열 함수 外


size_t strlen ( const char * str );

문자열의 실제 길이를 리턴하는 함수이다. 널문자를 제외한 길이라는 점에 주의하자!!! 참고로 size_t 란건 unsigned int를 재정의한 것이다. 






int strcmp ( const char * str1, const char * str2 );

두개의 문자열을 비교하여 동일할 경우 0이 리턴되고, str1이 클 경우 양수, str2가 클 경우 음수가 리턴된다. 여기서 크다는 것은 문자를 아스키 코드값으로 비교한 결과를 말하는 것이다.






errno_t strcpy_s(
   char *strDestination,
   size_t numberOfElements,
   const char *strSource 
);
문자열을 복사하는 strcpy의 새로운 표준형이다. strcpy의 경우 배열의 첨자범위를 넘어설 위험성이 많으므로 최근의 visual studio에서 사용하면 경고 메시지가 뜬다. 중요한건 두번째 인자가 Dest 버퍼의 크기라는 점만 알면 된다. errno_t는 에러체크를 위해 사용되는 리턴값 같은데 실제 사용할때는 신경안써도 된다.


errno_t strcat_s(
   char *strDestination,
   size_t numberOfElements,
   const char *strSource 
);
복사가 아니라 이어붙이기. 나머지 설명은 위와 동일.









아래는 실제로 문자열을 깊은 복사할때의 코드이다.
가장 주의해서 볼 점은 strlen() 함수는 NULL 문자를 제외한 길이를 리턴한다는 점이다.



char szTemp[256];
cin >> szTemp;


int nLen = strlen(szTemp);


char* m_szName = new char[nLen + 1];


strcpy_s(m_szName, nLen + 1, szTemp);








※ 문자열 함수는 아니지만 콘솔 문자열 입력 관련

cin 객체는 한 개의 문자 단위로 입력받아 처리하며, 공백문자나 개행문자(엔터, '\n')로 tokening 된다.
이때 두 개 이상의 문자를 입력하면 그만큼 예외처리가 여러번 일어나는 것을 볼 수 있다.
이것을 막으려면 입력버퍼를 초기화시키는 fflush(stdin); 명령을 사용하면 편리하다.

cin.getline()  공백문자 포함해서 콘솔에서 문장을 입력받아 저장하는데 사용하는 함수





※ 참조:
http://www.cplusplus.com/
http://msdn.microsoft.com

[C++] 연산자 오버로딩


OperatorOverLoad OperatorOverLoad::operator+( const OperatorOverLoad& rhw)
{
OperatorOverLoad temp;
temp.BindXY(m_nX + rhw.m_nX, m_nY + rhw.m_nY );
return    temp;
}



위는 m_nX와 m_nY 두개의 멤버 변수를 가진 클래스에서의 '+' 연산자 오버로딩의 예시이다.

그런데 사실 이건 중요하지 않고ㅡ,.ㅡ;;

복사생성자 관련 포스트에서도 언급한것 같지만 '=' 연산자 오버로딩이 중요하다.





OperatorOverLoad OperatorOverLoad::operator=( const OperatorOverLoad& rhw)
{
///< 자기 자신 확인 
if( this == &rhw )
{
return *this;
}

///< 확인 
SetName(rhw.m_pName);


return *this;
}




void OperatorOverLoad::SetName(const char* pName)
{
///< 포인터 검사 
if( pName != 0 )
{
int nLen = strlen(pName);
if( nLen != 0 )
{
delete [] m_pName;
m_pName = NULL;


m_pName = new char[nLen + 1];
strcpy_s(m_pName,nLen+1,pName);
}
}
}



위 내용을 요약하자면 char* 형의 멤버변수에 대하여 깊은 복사를 해주고 있다.

char* 형의 멤버변수가 존재할 경우 깊은 복사를 하도록 복사생성자와 '=' 연산자 오버로딩을 둘 다 생성해주어야 한다.

[C++][디자인패턴] static과 싱글톤 패턴

디자인 패턴이란

프로그래머들이 프로젝트를 하면서 자주 사용되는 몇가지 유용한 프로그램 스타일 들에 이름을 붙여서 분류한 것이다. 싱글톤, 팩토리, 옵저버, 커맨드, 상태 패턴 등이 있다. 각 패턴들이 어떤 상황에서 사용되는지를 아는 것이 중요하다.



싱글톤 패턴의 특징

-싱글톤은 매니저 역할을 하는 패턴이다.
-단 하나만 존재하는 전역 클래스이다.
-함수와 변수를 static으로 선언하여 사용한다.




<cStudentMgr.h>


#pragma once


class cStudentMgr
{
private:
static cStudentMgr* m_pInstance;
int m_nID;

public:
static cStudentMgr* GetInstance(void);
void Destory(void);


inline void SetID(int nID)
{
m_nID = nID;
}


inline int GetID(void) const
{
return m_nID;
}


private:
cStudentMgr(void);
~cStudentMgr(void);
};





위 코드를 보면 생성자와 소멸자가 private 영역에 들어가 있다.
이런 경우 클래스의 객체를 만들면 생성자와 소멸자가 private이므로 호출할 수 없다는 에러가 발생한다.
생성자와 소멸자 대신에 GetInstance(), Distroy()를 사용해 프로젝트를 통틀어 단 하나의 객체만을 생성한다.
두 함수의 내부 구현은 이렇다.




<cStudentMgr.cpp>



#include "cStudentMgr.h"


///< 정적 초기화 
cStudentMgr* cStudentMgr::m_pInstance = 0;


cStudentMgr::cStudentMgr(void)
:m_nID(0)
{
}


cStudentMgr::~cStudentMgr(void)
{
}


///< 싱글톤 인스턴스 포인터 얻기 
cStudentMgr* cStudentMgr::GetInstance(void)
{
///< 처음 이라면 
if( m_pInstance == 0 )
{
m_pInstance = new cStudentMgr;
}


return m_pInstance;
}


///< 생성된 static 인스턴스 삭제
void cStudentMgr::Destory(void)
{
if( m_pInstance != 0 )
{
delete m_pInstance;
m_pInstance = 0;
}
}






가장 위는 정적변수의 초기화이다.
생성자와 소멸자보다 위의 정적영역에서 초기화되고 있다.

(참고로 생성자에서 강조된 부분은 멤버 이니셜라이저라고 하는데, const 나 레퍼런스 변수처럼 선언과 동시에 초기화되어야 하는 변수들을 클래스에서 초기화해주는 방법이다. 여기서는 굳이 사용할 이유는 없지만 그냥 사용하고 있다-ㅅ-; 또한 상속시에 부모 생성자에 인자를 넘길때도 사용된다.)

그리고 아래 2개의 함수는 단 하나의 객체만을 생성 & 소멸시키는 기능을 하고 있다.
메인함수에서는 아래와 같이 사용된다.




#define ST_MGR cStudentMgr::GetInstance()   /// 사용하기 편리하도록


int main(void)
{
ST_MGR->SetID(1);


cout << ST_MGR->GetID() << endl;

ST_MGR->Destory();


return 0;
}




싱글톤패턴은 프로젝트에 단 하나뿐인 전역 클래스로서 주로 관리자 역할을 하는 클래스를 만들어 사용하는 방식이다.
static 이므로 객체 생성없이 정적 영역의 멤버변수와 함수를 어디서나 호출하여 사용할 수 있다.
특징은 전역변수와 마찬가지로 사용하기엔 편리하지만 남용할 경우 유지보수, 가독성, 재사용성 등에 문제가 발생한다.
따라서 프로젝트당 단 하나의 클래스만 전역으로 만드는 것이 좋으며, 프로젝트 팀장의 성향에 따라 싱글톤을 아예 못쓰게 하는 경우도 있다고 한다.




※ 참고: 정적(static) 함수란?
개념적으로는 정적 멤버변수만을 접근 가능한 함수이다.
클래스가 인스턴스되지 않아도 사용가능하다.
내부적으로는 다른 멤버함수와 달리 this 포인터를 넘기지 않는다.
때문에 c에서 callback으로 넘길때 유용하다(이건 아직 무슨 말인지 모르겠다).
this 포인터가 없으므로 상속해서 오버라이딩 불가능.
또한 c에서는 하나의 파일에서만 해당 함수를 사용하고 싶을때 static을 붙인다.

2012년 2월 20일 월요일

포풍같은 주말을 보내고..

뭐랄까.. 평생 다시 이런 일이 없을지도 모르는 주말이었는데

뭔가 완전히 불태우지 못한것 같아서 아쉽고 또 아쉬움만 남는다.

그래도 감동이었고...

뭔가 응어리같은게 풀린 느낌.. 죽어도 여한이 없다? 까지는 아니지만..ㅎㅎ

콘서트란건 한번은 좌석에서 전체를 보고 한번은 스탠딩을 뛰는것이 진리구나 라고 깨달음ㅋㅋ

아... 주말부터 오늘까지는 아무것도 손에 안잡혔다.

지금 해야할게 많은데...

그냥 에헤라디야 딩가딩가 하면서 살면 안될까요?





2012년 2월 15일 수요일

[C++][클래스] this 포인터

지난 포스트에서 const 인자 관련해서 this 라는 알 수 없는 녀석이 등장했었다.
이번엔 그것을 정리해보겠다.



일단 정의부터,

객체의 멤버함수는 자신을 소유한 객체의 주소를 가리키는 this 라는 포인터를 자동으로 가지게 된다.



예를 들어 아래와 같이 멤버함수를 실행했다고 하자.

int main()
{
    TestClass c1;

    c1.TestFunc();            // *

    return 0;
}


위의 별표로 표시한 라인이 실행될때 자동으로 this 포인터가 생성이 되고 그것이 함수 내부에 인자로 들어간다.

더 자세히 보자면 



TestClass* const this = &c1;             // 가리키는 객체를 바꾸면 안되므로 const
//const TestClass* const this = &c1;    // const 함수의 경우 멤버 변수도 바꾸면 안되므로 또 const



함수 호출시 자동으로 위 선언이 실행되고 
TestFunc() 함수 내부에 this가 인자로서 전달된다.
즉, TestFunc() 내부에서 아래와 같이 this를 사용할 수 있다.



TestFunc()
{
    cout << this->m_ID;
}






※ 보충설명:
컴퓨터 내부적으로는 각 객체에 대하여 멤버변수는 각각 메모리를 할당받지만 멤버함수는 그렇게 할 필요가 없다. 어차피 같은 내용이므로 메모리 낭비가 되기 때문이다. 그렇기 때문에 실제 메모리상에 멤버함수의 코드부분을 저장하는 곳은 클래스당 한 곳만 존재하면 되지만, 대신에 각 멤버함수를 객체별로 구분하기 위하여 this 포인터의 개념이 도입된 것이다. [참조: 뇌를 자극하는 C++, p.622]





[C++][클래스] 복사 생성자

복사 생성자의 형태는 아래와 같다.


클래스명(const  클래스명&  name)
{
         /// 내용
}



- 인자가 레퍼런스인 이유는?
인자를 직접 복사받아서 사용한다면 복사생성자 내에서 다른 복사생성자를 호출하고 그 복사 생성자가 다시 다른 복사생성자를 호출하는 무한 루프 상황이 발생할 수 있으며, 그때 실제 메모리 복사가 일어나므로 메모리 오버플로우 등의 에러가 발생할 수 있기 때문이다.
레퍼런스의 경우 메모리에 실체가 복사되는 것이 아니므로 안전하다.



- 복사 생성자를 정의하는 이유?
클래스에 char* 처럼 메모리 동적할당을 받는 멤버변수가 있을 경우, 반드시 복사 생성자를 직접 정의하여 '깊은 복사'를 해줘야한다.

이때 복사생성자와 쌍으로 대입연산자(=)를 오버로딩하여 마찬가지로 깊은 복사를 하도록 정의해 주어야 한다.

참고로 깊은 복사란 메모리 공간을 별도로 할당 받고 그 내용을 복사받는 형태, 얕은 복사는 포인터가 가리키는 주소값 자체를 복사해 오는 것이다.
디폴트 복사 생성자는 얕은 복사를 하는데, 이 경우 같은 주소를 여러개의 다른 객체가 가리키는 것이므로 각각의 객체가 소멸될때마다 delete 명령어로 같은 메모리를 여러번 삭제하는 위험한 사태가 발생할 수 있게 된다.



- 복사 생성자가 호출되는 3가지 경우

1. 객체를 선언하고 초기화 할때

cTestClass tc1;
cTestClass tc2 = tc1;         // 여기서 호출된다.


2. 함수 인자로 객체가 복사되어 들어갈때(임시객체 생성)

void   TestFunc(TestClass tc);


3. 함수에서 객체를 값으로 복사해서 리턴할때(임시객체 생성)

TestClass  TestFunc();











[C++][클래스] 객체 레퍼런스를 인자로 받을때 const 사용시 에러발생 문제


// 다른 객체에서 정보 복사해오기
//void cStudentInfo::CopyInfo(const cStudentInfo& c)
void cStudentInfo::CopyInfo(cStudentInfo& c)
{
char* newID = c.GetID();
char* newName = c.GetName();
int newKorPnt = c.GetKorPoint();
int newEngPnt = c.GetEngPoint();
int newMatPnt = c.GetMatPoint();


SetID(newID);
SetName(newName);
SetKorPoint(newKorPnt);
SetEngPoint(newEngPnt);
SetMatPoint(newMatPnt);
}



위의 코드는 클래스 멤버함수의 정의부이다.
자신과 동일한 클래스 타입 객체 레퍼런스를 인자로 받아 내용을 복사하는 함수인데
인자에 const를 붙이면 Getxxx() 함수를 사용할때 아래와 같은 에러가 난다.



1>c:\documents and settings\baikanp\my documents\visual studio 2008\projects\120214\report.cpp(146) : error C2662: 'cStudentInfo::GetID' : 'this' 포인터를 'const cStudentInfo'에서 'cStudentInfo &'(으)로 변환할 수 없습니다.



const를 제거하면 정상적으로 빌드가 되며,
참고로 Getxxx() 함수는 단순히 멤버변수를 리턴하는 함수이다.








남쌤에게 문의한 결과,
const로 선언하면 cStudentInfo& c 가 절대 변하지 않는다는 보장을 해준 것인데, 
c.Getxxx() 함수를 사용할 때 임시객체의 생성과 소멸 등이 발생하여 객체에 변경이 생기기 때문에 에러가 나는 것이라 한다.
지금으로서는 확실히 이해가 안되지만 Getxxx() 함수를 사용하는 것이 객체에 변경을 가져온다는 것으로 이해면 될것같다.
아마도 에러메시지로 보건데, 객체에 암묵적으로 포함된 this 라는 포인터가 변경되는 것이 직접적인 에러의 원인인듯 하다.




해결법은 두가지이다. 
가장 위의 코드처럼 const를 제거하거나, 
또는 아래와 같이 Getxxx() 함수를 거치지 않고 직접 멤버변수를 복사하는 것이다.



void cStudentInfo::CopyInfo(const cStudentInfo& c)
{
char* newID = c.m_szID;
char* newName = c.m_szName;
int newKorPnt = c.m_nKorPoint;
int newEngPnt = c.m_nEngPoint;
int newMatPnt = c.m_nMatPoint;






여기서 또 한가지 재밌는 것은 위 멤버 변수들은 private 로 선언되어 있다는 것이다.
즉,  어떤 객체의 메소드는 같은 타입 다른 객체를 인자로 받았을 때 그  private 멤버변수를 자유롭게 접근할 수 있다는 것이다.
(예를 들어 복사 생성자의 경우도 함수 내부에서 타 객체의 멤버를 직접 접근하고 있다.)








※ 내용보충 (2012. 02. 16):
const 객체를 사용해서 const가 아닌 멤버함수를 호출하는 것은 불가능하다. 컴퓨터는 const가 아닌 멤버함수는 멤버변수의 값을 변경한다고 생각하기 때문이다(뇌를 자극하는 C++ p.599). 위 문제의 경우 Get 함수들을 아래와 같이 const 함수로 선언해주면 const 객체를 통해서 사용해도 에러가 생기지 않는다. 참고로 const 함수란 멤버변수의 값을 변경하지 않는 함수를 말한다.




char* cStudentInfo::GetID(void) const

2012년 2월 14일 화요일

[포토샵] 강의내용 정리2 - 브러시


* 브러시

윈도우 -> 브러시 (F5) 옵션에서

shape dynamic: 브러시 경계모양을 조절, 브러시 외곽 모양을 찌그러뜨리는 형태
scattering: 점을 뿌려주는 효과
texture: 질감을 브러시에 적용
dual brush: 두개의 브러시를 합성모드와 크기, 간격 등을 조절
color dynamics: 브러시의 명도, 채도, 색상을 조절
other dynamics: 브러시의 투명도와 흐름

noise: 브러시 경계부분을 거칠게 표현
wet edges: 수채화 느낌
air brush: 압력을 감지할 수 있는 브러시(위쪽 툴바에서 그림 클릭)
smoothing: 브러시 모양을 부드럽게
project texure: 브러시에 적용된 패턴의 크기와 모양을 일정 조절


----------------------
-이미지로 브러시 모양 만들기: 이미지를 띄워둔 상태로 에디트 -> 디파인 브러시 프리셋

-브러시 패턴(.abr 파일) 불러오기: 브러시 팁 선택화면 우상단 화살표 클릭하고 로드 브러시 선택


----------------------
-히스토리 브러시: 그림을 원래 상태로 되돌림(예: 이미지를 흰색으로 덮은 뒤 히스토리 브러시로 흰색을 지워주는 효과)

-아트 히스토리 브러시: 유화(?) 느낌으로 바꿔줌

[포토샵] 강의내용1 - 단축키外 (정리중)

*포토샵 버전에 대해

포토샵 CS3 & CS5: 안정화 버전으로서 CS5의 경우는 필요 사양이 조금 무거울 수 있다.

포토샵 CS4:           과도기의 불안정한 버전. 비추천.



*단축키 정리


UNDO, REDO 반복 ctrl + z
무한 UNDO ctrl + alt + z
무한 REDO         ctrl + shift + z

※ Ctrl + K 로 Preference (설정창) 들어가서 Performance 탭의 History State를 조정하면 몇번까지 UNDO가 가능한지 지정할 수 있다.
※ 윈도우 -> 히스토리 창을 열어서 실행취소할 수도 있다.


확대 컨트롤 + 플러스
축소 컨트롤 + 마이너스
원본크기로 ctrl + alt + 0

전경색채우기 alt + del
배경색채우기 ctrl + del

화면움직이기 스페이스바 (창크기보다 큰 그림을 볼 때)

불러오기 화면 더블클릭 (Ctrl + O)
새 그림 ctrl + 화면 더블클릭 (Ctrl + N)

다른이름으로 저장 ctrl + shift + S
웹저장 ctrl + alt + shift + S


---------------------------------
Ctrl + U 색상변경메뉴 (선택범위의 색상, 채도, 명도 등을 조절)
Ctrl + L  레벨 창. 밝기조절 (ctrl +shift + L 오토레벨)
Ctrl + M 커브즈 창. 명암 조절 등 (※팁: 선을 살짝 S자 곡선으로 하면 사진이 예쁘게 나옴)
Ctrl + M 텍스트 옵션 창


Ctrl + Shift + U 선택영역 흑백화
Ctrl + Shift + i 선택영역 반전
색 반전 Ctrl + i


[ , ] (대괄호) 브러쉬, 펜 크기 조절


------------------------
포토샵 실행 직후 설정 초기화 Shift + Ctrl + Alt

커서모양변경 Caps Lock

줄자 보이기 Ctrl + R


------------------------
전체 속성(preferences)         ctrl + K


회전, 크기조절                     ctrl + T

선택영역 안쪽으로 붙여넣기 ctrl + shift + v

------------------------
*기타


-도트 느낌을 유지하면서 이미지 확대할때: 이미지 크기 변경창 제일 밑에서 원본 보존 항목 선택

-전체 속성 창에서 General -> Image Interpolation 에서 가장 위 항목을 적용하면 안티알리아싱이 적용되지 않게 된다. 2D게임 도트 리소스를 따고 싶을때는 이미지 경계면이 확실해야 하므로 이렇게 설정해 주는것이 좋다.

블로그 시작~!!

블로그니 싸이월드니 네이트온이니 아무것도 안하는 온라인 은둔형인 내가 드디어 SGA 남쌤 권유에 따라 블로그를 시작하게 되었다..

일단은 주로 프로그래밍 관련 공부한 내용을 정리하는 일기장과 같은 용도로 사용하게 될 것같다.

그럼 블로그 개설을 자축하는 의미에서 일단 그림 한장~