Visual Studio 2010 공식 팀 블로그 @vsts2010

Posted by 흥배

요즘 바쁘다 보니 아주 오랜만에 글을 올리게 되었습니다^^;

이번 시간에는 chrono를 사용하여 시간 계산에 대해서 간단하게 설명 하겠습니다.

 

이전 시간에서 보았듯이 chrono는 아래와 같이 다양한 타입으로 시간을 표시할 수 있습니다.

 

boost::chrono::nanoseconds  // 나노 세컨드. 10억분의 1

boost::chrono::microseconds // 마이크로 세컨드. 100만분의 1

boost::chrono::milliseconds  // 밀리 세컨드. 1000분의 1

boost::chrono::seconds      //

boost::chrono::minutes      //

boost::chrono::hours        //

 

 

각 시간 타입 별로 생성할 때 값을 설정할 수 있습니다.

boost::chrono::hours H1(1); // 1시간

boost::chrono::hours H2(2); // 2시간

boost::chrono::hours H25(25); // ?

 

boost::chrono::seconds S1(10);

boost::chrono::seconds S2(120);

 

boost::chrono::milliseconds MILS1(100);

 위 코드의 H1이나 S1, MILS1은 문자열이나 숫자로 출력할 수 있습니다.(방법은 제일 아래의 예제 코드를 봐 주세요)

 

또한 이 시간 타입을 서로 연산할 수도 있습니다.

boost::chrono::hours H1(1);

boost::chrono::hours H2(2);

boost::chrono::hours H3 = H1 + H2;

 

물론 다른 시간 타입을 연산할 수도 있습니다

boost::chrono::seconds S1(10);

boost::chrono::milliseconds MILS1(100);

boost::chrono::milliseconds MILS2 = S1 + MILS1;

 

다른 시간 타입을 연산할 때 주의할 점이 있습니다. 아래처럼

boost::chrono::milliseconds MILS2 = S1 + MILS1;

의 경우는 초와 밀리세컨드라는 서로 다른 타입을 더하지만 값을 저장하는 타입이 밀세컨드이기 때문에 읽어버리는 값이 발생하지 않으므로 연산에 문제가 없습니다.

 

그러나 아래와 같이

boost::chrono:: seconds S2 = S1 + MILS1;

로 하는 경우는 밀리세컨드 부분을 잃어버리게 되기 때문에 컴파일 에러를 발생합니다.

이런 경우는 명시적으로 형 변환을 시켜줘야 합니다.

boost::chrono::seconds S2 = boost::chrono::duration_cast< boost::chrono::seconds >(S1 + MILS1);

 


< 예제 >

#include <boost/chrono.hpp>

int main()
{
    {
        boost::chrono::hours H1(1); // 1시간
        boost::chrono::hours H2(2); // 2시간
        boost::chrono::hours H3(25); // ?

        std::cout << "H1(1) - 문자열 : " << H1 << std::endl;
        std::cout << "H1(1) - 숫자로 : " << H1.count() << std::endl;
        std::cout << "H3(25) - 문자열 : " << H3 << std::endl;
        std::cout << "H3(25) - 숫자로 : " << H3.count() << std::endl;


        boost::chrono::seconds S1(10);
        boost::chrono::seconds S2(120);

        std::cout << "S1(10) - 문자열 : " << S1 << std::endl;
        std::cout << "S1(10) - 숫자로 : " << S1.count() << std::endl;

        std::cout << "S2(120) - 문자열 : " << S2 << std::endl;
        std::cout << "S2(120) - 숫자로 : " << S2.count() << std::endl;
    }

    {
        boost::chrono::hours H1(1);
        boost::chrono::hours H2(2);
        boost::chrono::hours H3 = H1 + H2;

        std::cout << "H1 + H2 = : " << H3 << std::endl;


        boost::chrono::seconds S1(10);
        boost::chrono::milliseconds MILS1(100);
        boost::chrono::milliseconds MILS2 = S1 + MILS1;

        std::cout << "S1 + MILS1 = : " << MILS2 << std::endl;


        boost::chrono::seconds S2 = boost::chrono::duration_cast< boost::chrono::seconds >(S1 + MILS1);

        std::cout << "S1 + MILS1 = : " << S2 << std::endl;
    }



    return 0;
}



 

 

저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

  1. You are completely right in such kind of technical points!

  2. I was searching for such a guide! It is very much clear to me

Posted by 흥배

chrono는 경과 시간을 계산할 때 다양한 시간 타입으로 계산할 수 있습니다.

이전 회의 예제의 경우는 초 단위로 표시하되 소수점까지 표시할 수 있었습니다.

boost::chrono::duration<double> sec = boost::chrono::system_clock::now() - start;

 

그런데 보통은 소수점이 나오는 결과 값보다는 정수로 나오는 값을 사용하는 경우가 많을 것입니다.

 

chrono에서는 경과 시간을 나타내는 클래스는 duration입니다.

duration 6개의 시간 단위를 지원합니다.

nanoseconds - 10억분의 1

microseconds - 100만분의 1

milliseconds - 1000분의 1

seconds –

minutes -

hours – 시간

 

이전 회의 예제를 사용하여 이번에는 다양한 시간 단위로 경과 시간을 표시해 보겠습니다.

#include <boost/chrono.hpp>

#include <cmath>

 

void Test()

{

           for ( long i = 0; i < 10000000; ++i )

           {

                     std::sqrt( 123.456L );

           }

}

 

int main()

{

    boost::chrono::system_clock::time_point StartTime = boost::chrono::system_clock::now();

                    

    Test();

    boost::chrono::system_clock::time_point EndTime = boost::chrono::system_clock::now();

 

    boost::chrono::duration<double> DefaultSec = EndTime - StartTime;

    boost::chrono::nanoseconds nano = EndTime - StartTime;

    boost::chrono::microseconds micro = boost::chrono::duration_cast<boost::chrono::microseconds>(EndTime - StartTime);

    boost::chrono::milliseconds mill = boost::chrono::duration_cast<boost::chrono::milliseconds>(EndTime - StartTime);

    boost::chrono::seconds sec = boost::chrono::duration_cast<boost::chrono::seconds>(EndTime - StartTime);

    boost::chrono::minutes min = boost::chrono::duration_cast<boost::chrono::minutes>(EndTime - StartTime);

    boost::chrono::hours hour = boost::chrono::duration_cast<boost::chrono::hours>(EndTime - StartTime);

 

    std::cout << "Test() 함수를 수행하는 걸린 시간 : " << DefaultSec.count() << " default" << std::endl;

    std::cout << "Test() 함수를 수행하는 걸린 시간 : " << nano.count() << " nanoseconds" << std::endl;

    std::cout << "Test() 함수를 수행하는 걸린 시간 : " << micro.count() << " microseconds" << std::endl;

    std::cout << "Test() 함수를 수행하는 걸린 시간 : " << mill.count() << " milliseconds" << std::endl;

    std::cout << "Test() 함수를 수행하는 걸린 시간 : " << sec.count() << " seconds" << std::endl;

    std::cout << "Test() 함수를 수행하는 걸린 시간 : " << min.count() << " minutes" << std::endl;

    std::cout << "Test() 함수를 수행하는 걸린 시간 : " << hour.count() << " hour" << std::endl;

                    

    return 0;

}

 

< 결과 >


 


 ps : 네임스페이스를 다 적다보니 코드 가독성이 좀 떨어질텐데 양해바랍니다^^;

저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

  1. 이 나오는 결과 값보다는 정수로 나오

Posted by 흥배

chrono Boost 라이브러리 1.47에서 새로 생긴 시간 측정 라이브러리입니다.

chrono C++11 STL에 들어갔습니다. 그래서 C++11을 완벽하게 지원하는 컴파일러가 나오지 않은 때라도 Boost 라이브러리를 사용하면 미리 사용해 볼 수 있습니다. 그리고 컴파일러에서 C++11 chrono를 지원한다면 손쉽게 표준으로 바꿀 수 있습니다.

 

chrono를 사용하면 특정 시간 구간에 걸린 시간을 세컨드(), 밀리 세컨드, 나노 세컨드로 얻을 수 있으며 또 시간끼리 연산을 할 수도 있습니다

 

 

chrono 사용 방법

chrono는 시스템 API를 사용하므로 먼저 Boost 라이브러리의 lib 파일이 필요합니다. Boost 라이브러리를 다운로드 받아서 직접 빌드하던가 BoostPro를 통해서 이미 만들어진 lib 파일을 받아서 설치해야 합니다.

 

헤더 파일은

#include <boost/chrono.hpp>

만 추가하면 됩니다.

 

 

chrono를 사용한 성능 측정

프로그램의 성능 측정을 할 때 특정 기능을 시작하기 전에 현재 시간을 저장하고(S1), 그 기능을 다 수행한 후 현재 시간(S2)을 얻어서 S2-S1을 계산하여 걸린 시간을 얻습니다.

이런 기능을 chrono를 사용하여 간단하게 구현해 보겠습니다.

 

< 예제코드 1 >

#include <boost/chrono.hpp>

#include <cmath>

 

void Test()

{

           for ( long i = 0; i < 10000000; ++i )

           {

                     std::sqrt( 123.456L );

           }

}

 

int main()

{

    boost::chrono::system_clock::time_point start = boost::chrono::system_clock::now();

                

    Test();

          

    boost::chrono::duration<double> sec = boost::chrono::system_clock::now() - start;

    std::cout << "Test() 함수를 수행하는 걸린 시간() : " << sec.count() << " seconds" << std::endl;

 

    return 0;

}

 

< 실행 결과 >

 

<예제코드 1>에서는 boost::chrono::system_clock::now()을 사용하여 현재 시간을 얻습니다.

boost::chrono::system_clock::time_point start = boost::chrono::system_clock::now();

여기서 time_point 타입은 시간 상의 한 축을 뜻합니다.

 

이후 Test() 함수를 실행한 후 다시 현재 시간을 얻은 후 Test()를 시작하기 전에 저장한 현지 시간을 빼면 Test()를 수행하는 걸린 시간을 얻을 수 있습니다.

boost::chrono::duration<double> sec = boost::chrono::system_clock::now() - start;

 

이번 회는 이정도로 아주 간단하게 chrono에 대해서 설명하겠습니다. chrono의 더 다양한 기능은 다음 회에 또 설명하겠습니다^^

 

ps) boost::chrono::system_clock::now()에 의해서 얻는 시간의 초기 시간은 1970년 입니다.

저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

  1. 실질적으로, 기사는이 칭찬할만한 주제에 정말 최고입니다. 당신의 결론에 동의하고 열심히 미래의 업데이 트를 기대합니다. 그냥 당신이 그냥 서면으로 멋진 명석을 위해 충분하지 않습니다 감사합니다라고. 나는 즉시 만족 일과 비즈니스 노력에 많은 성공을 것입니다.

  2. 미래의 업데이 트를 기대합니다. 그냥 당신

Posted by 흥배

혹시 Boost 라이브러리라는 것을 아시나요? 만약 아직 모르고 있었다면 C++ 프로그래머로서 적지 않은 손해를 보고 있다고 생각합니다.^^

Boost 라이브러리는 C++ 프로그래머를 위한 유용한 오픈 소스 C++ 라이브러리 모음입니다. Boost 라이브러리 개발에 수 많은 C++ 고급 프로그래머들이(C++ 표준 위원회 멤버 등) 참여 하고 있습니다. 그래서 Boost 라이브러리는 실용적인 기능과 높은 안정성을 가지고 있습니다.

 

만약 아직까지 Boost 라이브러리를 한번도 사용해 본적이 없다면 바로 사용하기를 권합니다. 그리고 아직도 일부에서는 Boost 라이브러리의 안정성에 대해서 의심하는 분들이 있는데 무의미한 의심은 그만두기를 바랍니다^^

 

C++11에 들어가는 새로운 표준 라이브러리에는 Boost 라이브러리에 있는 것들이 많이 들어갔습니다. 예를 들면 VS 2008 SP를 설치하면 사용할 수 있는 tr1 라이브러리에 있는 대부분이 Boost 라이브러리에 있는 것입니다. 새로운 표준에는 들어갔지만 아직 VC++에서 지원하지 않는 라이브러리도 Boost 라이브러리를 사용하면 미리 사용해볼 수 있습니다.

 

다음에 소개할 chrono Boost 라이브러리에 이미 있습니다. 그러니 Boost 라이브러리를 설치하면 chrono는 바로 사용해 볼 수 있습니다.

 

Boost 라이브러리의 설치와 사용 방법은 구글링을 하면 적지 않게 찾을 수 있습니다. 그 중 몇 개를 제가 찾아 놓았습니다^^

 

 

Boost 라이브러리 홈페이지

http://www.boost.org/

최신 버전은 1.47.0 입니다.

 

 

VC++ 6.0에서 Boost 라이브러리 설치

- 1.33 버전까지만 설치할 수 있습니다

http://blog.naver.com/sorkelf/40132524363

 

 

설치 파일로 설치하기 (VC++ 7.1 ~ VC++ 10까지 지원)

- Boost 라이브러리는 대부분의 기능은 헤더 파일 추가만으로 사용할 수 있지만 일부 기능(thread, filesystem ) lib 파일을 만들어야 합니다. 그러나 설치 파일로 설치하면 이미 빌드된 lib 파일을 얻을 수 있습니다.

http://ncanis.tistory.com/333

 

 

수동으로 설치하기

- 가장 기본 적인 방법으로 직접 lib 파일을 만들어야 합니다. 위의 설치 파일보다 장점은 lib 파일을 빌드할 때 옵션을 마음대로 지정할 수 있고, 특히 가장 최신 버전을 빨리 사용할 수 있습니다.

http://genkino.tistory.com/1446

 

 

Boost 라이브러리 설명

- 몇 년 전에 제가 번역한 것으로 1.33 버전을 기준으로 하고 있습니다. 설명에 부족한 것이 많지만 그런 부분은 구글링을 찾아보시기 바랍니다.

http://jacking75.cafe24.com/Boost/libraries.htm

 

 

Boost 라이브러리 e-book

- 영어라는 단점(?)이 있지만 각 기능을 잘 설명하고 있습니다.

http://en.highscore.de/cpp/boost/

 


꼭 Boost 라이브러리를 설치하고 사용하기를 강력하게 추천합니다

저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

  1. 가장 기본 적인 방법으로 직접 lib 파일을 만들어야 합니다

Posted by 흥배

unscoped enumeration scoped enumeration

C++11(새로운 C++ 표준의 이름) enum은 지금(C++03)과 다르게 두 가지의 enum이 있습니다.

바로 unscoped enumeration scoped enumeration 입니다.

 

unscoped enumeration은 기존의 enum과 비슷한 것 이라고 생각 하면 되고, scoped enumeration C++11에서 새로 생긴 enum 입니다.

 

unscoped enumeration은 아래와 같이 정의하고 사용합니다.

enum ITEMTYPE : short

{

   WEAPON,

   EQUIPMENT,

   GEM       = 10,

   DEFENSE,  // C++03까지는 에러이지만 C++11에서는 에러가 아님

};

 

사용은 아래와 같이

short ItemType = WEAPON;

또는

short ItemType = ITEMTYPE::WEAPON; // C++03에서는 에러

 

 

scoped enumeration은 아래와 같이 정의하고 사용합니다.

enum class ITEMTYPE : short

{

   WEAPON,

   EQUIPMENT,

   GEM       = 10,

   DEFENSE, 

}

 

사용은 아래와 같이 합니다.

short ItemType = ITEMTYPE::WEAPON;

그러나 아래는 에러입니다.

short ItemType = WEAPON;  // 에러

 

scoped enumeration unscoped enumeration와 다르게 ITEMTYPE를 생략하면 안됩니다. WEAPON이나 GEM ITEMTYPE의 범위 안에 있음을 가리킵니다.

그리고 enum class 대신 enum struct을 사용해도 괜찮습니다. 또 타입을 지정하지 않으면 기본으로 int 타입이 됩니다.

 

 

 

전방 선언

unscoped enumeration scoped enumeration 둘 다 전방 선언을 할 수 있습니다.

 

아래와 같이합니다.

enum ITEMTYPE : short;

enum class ITEMTYPE : short;

 

전방 선언을 할 때 unscoped enumeration은 타입 선언을 생략할 수 없지만 scoped enumeration은 타입 선언을 생략 할 수 있습니다.

 

 

 

형 변환

unscoped enumeration은 기존과 같이 암묵적으로 정수로 변환할 수 있습니다.

int i = WEAPON;

그러나 scoped enumeration은 명시적으로 타입 캐스팅을 해야합니다.

int i = static_cast<int>(ITEMTYPE::WEAPON);

 

 

 


참고

http://d.hatena.ne.jp/spinor/20110918/1316321563

 


저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

  1. 실질적으로, 기사는이 칭찬할만한 주제에 정말 최고입니다. 당신의 결론에 동의하고 열심히 미래의 업데이 트를 기대합니다. 그냥 당신이 그냥 서면으로 멋진 명석을 위해 충분하지 않습니다 감사합니다라고. 나는 즉시 만족 일과 비즈니스 노력에 많은 성공을 것입니다.

  2. 래의 업데이 트를 기대합니다. 그냥 당신

  3. 대법원은 그중 이미 중요한 부분 및 마케팅 전략의 주요 기반 중 하나가 발생했습니다. 현재, 사람들은 옵션의 충분한로 취급되었다. 인터넷을 통해 선택은 다시 성장하고있다.

  4. 경험을 바탕으로 좋은 홍보 자료가 너무 좋은 판매량을 높일 것입니다. 당신은 나쁜 판촉물 경우, 즉시 변경합니다. 기업의 많은이 새로운 사업을 구축할 오래 생각해야하지만, 뒤얽힌 때 판촉 비용이 없습니다.

  5. 기존 고객 유지는 새로운 고객을 찾는 데보다 훨씬 저렴합니다. 성공적인 비즈니스는 고객과의 관계를 구축하기 위해 노력 시작해야합니다.

  6. 이메일 마케팅은 회사와 클라이언트 간의 관계의 모든 측면을 측정할 수있는 유일한 기회입니다. 이메일 마케팅은 중요한 벡터 생성 웹 트래픽입니다. 판촉 모델의 상단 목록에서 많은 마케팅 이메일 마케팅 장소. 사용하는 전자 메일 마케팅 무게 그룹이 직접적인 마케팅 캠페인을 이동됩니다 찾는 정확하게 구성되어 있습니다.

Posted by 흥배

constexpr를 클래스에 사용


constexpr을 클래스에서 사용하면 클래스를 정수로 사용할 수도 있으며 메타 템플릿 프로그래밍에서는 이전에는 복잡하게 처리하던 것을 아주 간단하게 처리할 수도 있습니다. C++ 메타 템플릿 프로그래밍에 관심이 많구나 자주 사용하고 있는 분들에게는 constexpr 덕분에 프로그래밍이 한결 편해지리라 생각합니다.

 

아래의 코드는 Integer 이라는 클래스를 constexpr을 사용하여 정수처럼 사용 합니다.

class Integer

{

private :

    int value ;

 

public :

    constexpr Integer() : value() { }

    constexpr Integer( int value ) : value(value) { }

 

    constexpr operator int() { return value ; }

} ;

 

int main()

{

    constexpr Integer size = 5 ; // 컴파일 타임에 정수로

 

    int x[size] ; // Integer::operator int()가 호출된다

 

    Integer object ; // 일반적인 클래스 인스턴스 화. 실행 시에 처리

    int y[object] ; // 당근 에러

}

출처 : http://cpplover.blogspot.com/2010/11/gccniconstexpr.html

 


또 메타 템플릿 프로그래밍에서는 아래와 같이 사용할 수도 있습니다.

#include <iostream>

 

struct pi {

    static constexpr double value = 3.14;

};

 

template <const double& r>

struct circle_area {

    static constexpr double value = r * r * pi::value;

};

 

struct radius {

    static constexpr double value = 2.5;

};

 

int main()

{

    constexpr double result = circle_area<radius::value>::value;

 

    static_assert(result == 19.625, "not equal");

    std::cout << result << std::endl;

}

출처 : http://d.hatena.ne.jp/faith_and_brave/searchdiary?word=constexpr&.submit=%B8%A1%BA%F7&type=detail

 

 

constexpr은 컴파일 할 때 결과가 이미 결정 나는 것은 컴파일 타임 때 처리를 해주어 실행 시에 불필요한 처리를 막아주고, 기존의 메타 템플릿 프로그래밍으로 까다롭게 만들었던 것을 아주 쉽게 구현할 수 있게 해줍니다.

 

C++11에서는 constexpr을 잘 사용하면 기존 보다 더 뛰어난 프로그래밍을 할 수 있으니 깊게 파고들 가치가 있다고 생각합니다.

저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

  1. 일 할 때 결과가 이미 결정 나는 것은 컴파일 타임 때 처

Posted by 흥배

constexpr는 변수, 함수, 클래스를 컴파일 타임에 정수로 사용할 수 있도록 해줍니다. 즉 상수로 취급할 수 있는 작업은 컴파일 타임에 처리하도록 할 수 있습니다.

 

constexpr를 변수에 사용

constexpr int aa = 11;

이것은

const int aa = 11

와 같은 의미를 가집니다.

 

그러나 아래와 같이는 사용할 수 없습니다.

int input_num = 0;

constexpr int aa = input_num;  // 에러


constexpr
로 지정된 변수는 꼭 컴파일 시에 정수가 되기 때문에 변수 선언 시 대입이 정수 식이어야만 합니다. const와의 차이는 const는 컴파일 시에 정수가 아니어도 괜찮고 변수 선언 시 대입 값이 정수 식인 경우 정수 식이 되고, 그렇지 않은 경우는 단순히 const를 수식하는 것이 됩니다(이에 비해 constexpr는 꼭 정수 식이어야만 합니다).

 

 

 

constexpr를 함수에 사용

C++03에서는 아래의 코드는 에러가 됩니다.

int GetNum() { retun 5; }

int Numbers[ GetNum() ];

GetNum 함수는 상수 5를 반환 하는 것으로 이미 컴파일 시에 반환 값을 알 수 있습니다. 그러나 컴파일러는 GetNum 이라는 함수가 정수처럼 사용할 수 있는지 알 수 없으므로 정수로 취급하지 않습니다.

 

위 코드는 C++11constexpr를 사용하면 우리가 원하는 대로 GetNum 함수를 정수로 사용할 수 있습니다.

 

constexpr int GetNum() { retun 5; }

int Numbers[ GetNum() ];

 

constexpr를 함수에 사용할 때는 꼭 함수 본체는 { return expression; } 형태가 되어야만 합니다.

 

 

constexpr 변수는 비 constexpr 변수에 사용할 수 있으므로 아래와 같은 테크닉도 사용할 수 있다.

constexpr double power( double x, unsigned int y )

{

    return y == 1 ? x : x * power( x, y - 1 ) ;

}

 

int main()

{

    // 정수 식

    constexpr double a = power( 2, 32 ) ;

 

    // 정수 식이 아니다

    double x = 2 ; unsigned int y = 32 ;

    double b = power( x, y ) ;

}

(출처) http://cpplover.blogspot.com/2010/11/gccniconstexpr.html

 

 

그리고

const int base_HP = 200;

int NPC_Lv1_HP = base_HP + 0;

int NPC_Lv2_HP = base_HP + 200;

라는 코드는 정수 계산을 하는데 실행 시에 계산되는데 이것을 constexpr을 사용하여 컴파일 시에 계산되게 할 수 있습니다.

 

constexpr int AssignHP( int nPlusHP )

{

 return base_HP + nPlusHP;

}

 

int NPC_Lv1_HP = AssignHP( 0 );

int NPC_Lv2_HP = AssignHP( 200 );



 

저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

  1. 시에 정수가 되기 때문에 변수 선언 시 대입이 정

Posted by 흥배

현재의 표준 C++에서는 부모 클래스의 특정 멤버를 오버라이드 할 때 virtual을 앞에 붙입니다.

struct Base

{

  virtual void foo( int i );

};

 

struct Derived : Base

{

  virtual void foo( int i );

}

 위의 예제와 같은 작은 코드를 만질 때는 실수를 하지 않지만 실제 일을 할 때는 크고 많은 클래스를 다루다 보면 실수를 할 수 있습니다. 위 예제의 경우 아래와 같은 실수를 할 수 있습니다.

struct Derived : Base

{

  virtual void foo( float i );

}

위와 같이 실수를 하면 Derived의 foo 멤버함수는 Base foo 멤버함수를 오버라이드 하지 않게 됩니다. 이런 실수는 에러가 아니기 때문에 골치 아픈 삽질을 할 수도 있습니다.

이런 문제를 방지하기 위해서 override가 새로 생겼습니다.

struct Derived : Base

{

  virtual void foo( float i ) override;

}

이렇게 override를 사용하게 되면 컴파일 할 때 Base 클래스에

void foo( float i )가 없는데 오버라이드 한다고 에러를 발생시켜 줍니다.

 

 

때로는 Base 클래스의 특정 멤버함수를 Derived 클래스에서 오버라이드 하지 못하도록 막고 싶은 경우가 있을 것입니다. 이때는 final을 사용합니다.

struct Base

{

  virtual void foo( int i ) final;

};

 

struct Derived : Base

{

  virtual void foo( int i );

}

위의 코드에서는 Base 클래스의 foo 멤버함수를 final로 오버라이드 못하도록 해 놓았기 때문에 컴파일을 하면 에러가 발생합니다.

 

 

 

참고

위키피디아 http://en.wikipedia.org/wiki/C%2B%2B0x

 

저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

  1. final 저건 맘에 드네요. 지금까진 따로 __final___ 이라고 define 해서 썼는데. JAVA를 아는 사람이면 알아보리라는 기대감과 함께...

    근데 override 에서 virtual 키워드의 설명은 귀찮아서 대강 적으신듯. virtual 을 안써도 override 의 개념이긴 한데, 하긴 virtual 을 간단히 설명하기가 좀 애매하군요.

  2. override가 c++11에서 표준이 된건가요?

    기존에 vs2008에서 MS가 제공해주는 키워드인걸로 알고 있어서
    보기도 편하고 실수를 줄일수있어서 사용하던건데.....

    표준이 된거라면 환영~^^

  3. final 은 sealed 와 다른건가요?

    • 제가 알기로 sealed는 주로 자바와 C#에서 사용하는 것으로 알고 있는데 sealed는 다른 클래스가 이 클래스를 상속 하지 못하게 하는 것이고, final은 부모 클래스의 특정 멤버함수를 오버라이드 하지 못하게 하는 것입니다.

  4. 보기도 편하고 실수를 줄일수있어서 사

  5. 참조은 당신의 서비스 또는 제품을 사용할 수있을 그가 아는​​ 사람을 걱정하는 고객을 청할 때가 아닌 다른 누구도 없었다. 이 참조의 주요 아이디어는 사람이 참조된 연락을하는 것입니다.

  6. 허가 기반의 마케팅은 온라인 커뮤니케이 션에 추진 새 규칙이며, 당신이 말한 것을 관심을 자신의 중심에 따라 회사에서 상업용 전자 메일을 수신 안내서를 얻어 기반으로합니다.

  7. 어머니 또는 아버지는 젊은이의 필요성을 제공합니다.아이의 필요성은 시간이 지남에 많은 지네요. 그들은 모두 현금으로 준비한다.

  8. 모든 부모는 아이에게 장점을 제공합니다. 당신의 아이들은 최고의 수신을 직접 특정을 가지고. 젊은이를위한 가장 좋은 고가 하나의 특정 아닙니다.

  9. 부모는 아이들의 필요를 제공할 것입니다.아이들의 필요 년까지 많은 년을 받고있다. 그들은 돈으로 준비를해야합니다.

Posted by 흥배

새로운 C++ 표준 작업이 언제쯤에나 끝날지 고대하고 있는 분들에게 반가운 소식이 있습니다.

드디어 C++0x 작업이 거의 마무리 되었습니다.

 

저번 주 수요일에 최종 국제 투표가 끝난 후 드디어 결과가 나왔는데 만장 일치로 승인이 되었습니다. 이제는 앞으로 몇 달 후에 ISO로부터 최종 발행만 기다리면 됩니다(즉 서류적인 절차만 남았습니다).

 

이로써 길게 길게 진행된 C++의 새로운 표준 작업은 끝나게 되어서 이제 C++11로 불리게 되었습니다( 이전에는 C++98, C++03이 있었습니다 ).

 

C++은 특정 회사가 주도하지 않고, 기존에 C++로 만들었던 코드가 문제 없이 동작해야 하고(표준 사양만 지켰다면), 성능과 편리성을 모두 가지려고 하니 많은 시간이 걸렸습니다.

 

아직 ISO에서 최종 문서가 나오지 않았고 무료로 최종 사양이 어떻게 되었는지 궁금한 분들은 http://t.co/5mjCzyJ 를 통해서 문서를 받아보기 바랍니다. 이 문서는 워킹 드래프트 3242 ISO에서 나올 사양 문서와 거의 같을 것입니다(참고로 ISO에서 나온 문서는 유료입니다).

 

이제 우리는 앞으로 나올 Visual C++이 과연 얼만큼 새로운 표준 기능을 구현해 줄지가 기대됩니다. 개인적으로 꽤 많은 부분이 구현되리라 생각하고 혹 빠진 부분은 예전의 tr1처럼 서비스 팩에서 구현되지 않을까 생각합니다.

 

C++ 새로운 표준이 정해졌으니 남보다 앞서기를 바라는 C++ 프로그래머들은 새로운 C++ 표준을 공부해 봅시다. ^^

 

근래에 바빠서 글을 거의 올리지 못했는데 다음 글은 새로운 C++ 표준의 바뀐 부분을 간단하게 설명하는 글을 올릴 예정입니다.

그리고 새로 추가되는 표준 라이브러리는 boost 라이브러리에서 많이 들어왔습니다. 그래서 지금이라도 boost 라이브러리를 다운로드 받으면 새로운 표준에 들어갈 라이브러리를 미리 사용할 수 있습니다.

 

 


참고

C++0x 사양

위키피디아

http://en.wikipedia.org/wiki/C%2B%2B0x

GCC feature 테이블

http://gcc.gnu.org/projects/cxx0x.html

 

boost 라이브러리

설치 버전 다운로드

http://www.boostpro.com/download/

공식 홈페이지

http://www.boost.org

 

 

 

저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

  1. 내가? 그는 웹 사이트에 배포 꽤 제안을 발견으로 친구에게서 전화를 얻는 특권을 해요. 블로그 게시 주변 서핑하는 것은 일반적으로 정품 멋진 만남이다. 자신에 비해 어떤 측면에서 고객을 고려하고 많은 덕분에, 난 당신에게 전문 영역 것으로 승리와 관련된 최선을 열망.

  2. 려하고 많은 덕분에, 난 당신에게 전문 영

  3. 개인적으로 도서관에 와서 그것을 다운로드하여 직접 집에서 읽어 않고도 바로 거기에 책을 읽는 것을 선호합니다. 나는 도서관 상황은 조용하고 시원하고 편안한 사랑 해요.

  4. 감사의 뜻을 전달하기 위해, 우리는 특정 목표를 달성하기 위해 전세기 예약을 위해 신용 카드를 사용합니다. 그것은 고객이 제품을 구입하는 동기를 부여하실 수 있습니다.

  5. 이메일 마케팅은 회사와 클라이언트 간의 관계의 모든 측면을 측정할 수있는 유일한 기회입니다. 이메일 마케팅은 중요한 벡터 생성 웹 트래픽입니다. 판촉 모델의 상단 목록에서 많은 마케팅 이메일 마케팅 장소.

  6. 경력은 평범한 사람이 만족하는 무언가가 될 수 있습니다.성공 종래는 작업에서 볼 수 있습니다. 때때로, 사람들은 직업의 일부 형식을 무시합니다.

  7. 언어를 프로그래밍하는 것은 배울 매우 중요하는 것은 웹사이트를 개발하려는 것입니다. 그것은 처음에 매우 어려운 것입니다.

  8. 때때로 일이 일이 남자와 여자가 ​​펄럭 다네.경력은 남성과 여성들이 더 많은 수업을 잘하고, 믿게 수 있습니다. 그럼에도 불구하고 작업의 품질과 남성과 여성 행복하게 그 일을해야합니다.

  9. 직업은 그 사람들이 자랑스러운 일이 될 수 있습니다.번영의 기준은 작업에서 볼 수 있습니다. 때때로, 사람들은 일자리 특정 종류의 과소 평가.

Posted by 흥배

MSDN을 보다 보니 C++/CLI의 델리게이트에 네이티브용 함수를 할당할 수 있는 방법이 있어서 소개합니다. 아래의 코드는 MSDN에 있는 것입니다.

 

#pragma unmanaged

extern "C" void printf(const char*, ...);

class A {

public:

   static void func(char* s) {

      printf(s);

   }

};

 

#pragma managed

public delegate void func(char*);

 

ref class B {

   A* ap;

 

public:

   B(A* ap):ap(ap) {}

   void func(char* s) {

      ap->func(s);

   }

};

 

int main() {

   A* a = new A;

   B^ b = gcnew B(a);

   func^ f = gcnew func(b, &B::func);

   f("hello");

   delete a;

}

< http://msdn.microsoft.com/ja-jp/library/9cy3ccxx%28v=VS.80%29.aspx >

 

위 코드 중 #pragma unmanaged 지시어 이하는 컴파일러에서 비관리코드로 취급합니다. 그리고 #pragma managed 이하는 관리코드로 취급합니다. 내용이 간단하고 어려운 부분이 없기 때문에 따로 자세한 설명은 생략하겠습니다.

 


C++/CLI는 단순하게 닷넷 플랫폼에서 사용할 수 있는 C++ 언어라기 보다는 C++ 언어의 부족한 부분을 진화 시킨 언어라고도 생각할 수 있는 부분이 꽤 있습니다. 그러나 C++/CLI는 C++과 C#의 중간의 애매한 위치에 있어서 양쪽 프로그래머 모두에게 별로 호응을 받지 못하는 것 같습니다. 그래서 C++/CLI 관련 글을 제가 처음에 생각했던 것보다는 조금 일찍 끝낼려고 합니다.

C++/CLI를 사용하는 대부분의 프로그래머들은 아마 기존의 비관리 코드를 관리코드에서 사용하고 싶을 때라고 생각합니다. C++/CLI의 기능 소개는 이번으로 일단 끝내고 앞으로는 비관리코드와의 연계에 대해서 실제 사례 보여주면서 설명하려고 합니다.


사례는 오픈 소스 네트워크 라이브러리인 HalfNetworkC++/CLI를 사용하여 관리코드에서 사용할 수 있도록 wrapping한 후 이것을 관리코드에서 사용할 예정입니다.

HalfNetwork는 온라인 게임 서버 프로그래머인 임영기님이 만든 것으로 ACE 라는 오픈 소스 네트워크 라이브러리를 사용하기 편하게 만든 라이브러리입니다.

 

소스 위치 http://code.google.com/p/halfnetwork/

문서 http://code.google.com/p/halfnetwork/w/list http://jacking.tistory.com/category/HalfNetwork

임영기님 블로그 http://javawork.egloos.com/

 

요즘 공부할 것은 너무 많은데 따라갈 시간은 부족해서 다음 글은 언제쯤 올리지 정확하게 알 수 없지만 최대한 빨리 다음 글들을 올려서 C++/CLI을 2010년 안에는 끝내고 내년에는 새로운 주제로 시작하겠습니다^^

 

저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

  1. 많은 도움이 되었구요.
    글이 생각보다 짧아 진다니 좀 아쉽네요.
    기사 기대하고 있습니다.

    • 요즘 제가 바빠서 다음 글을 올리지 못하고 있습니다. 그래도 집에서 작업은 하고 있으니 곧 정리해서 올리겠습니다.^^

Posted by 흥배

119일에 오후 2시에 양재역 엘타워에서 한국 마이크로소프트와 인텔이 주최하고 월간 마이크로소프트웨어에서 주관한 ‘C++ & 게임 개발자를 위한 개발 생산성 및 퍼포먼스 향상 전략 세미나가 열렸습니다.

http://new.imaso.co.kr/seminars/game

 

아직 가을이지만 겨울이라는 생각이 들 정도로 추운 날씨였지만 많은 개발자 분들이 참석하셨습니다. 저는 요즘 회사가 바쁜 관계로 오전까지 일하다가 가서 좀 늦었더니 세미나 장은 이미 만원이더군요.

 


이 날 세미나에서 팀블로그에서 DX11을 연재하고 계신 박민근님과 제가 강연자로 참여했습니다. 박민근님은 예제로 느껴보는 DX11의 매력이라는 세션을 통해서 실제 DX11의 새로운 기능이 어떻게 사용되는지 보여주셨습니다. 원래 이날 실제 코드를 컴파일 해서 실행되는 모습을 보여 줄 예정이었지만 DX11을 지원하는 노트북을 구하지 못해서 안타깝게 집에서 찍은 영상으로 대체해서 보여주었습니다. 아마 다음에 DX11 관련 세미나가 있을 때는 컴파일 해서 돌아가는 모습을 볼 수 있을 테니 기다려주세요^^

제 시간에 가지 못해서 뒤에서 사진을 찍으니 박민근님이 작게 나오는군요^^;


15분인가 20분 정도 남을 때부터 5분 간격으로 남은 시간을 알려주더군요


저는 ‘C++ 프로그래머가 알아야 할 병렬 프로그래밍 상식이라는 주제로 병렬 프로그래밍과 관련된 하드웨어, 플랫폼, 아키텍처 그리고 용어나 Tip을 정리한 세션이었습니다. 강연 중 중앙의 스크린이 잠시 나가기도 하고고 10분을 남겨진 시점에서 노트북 밧데리가 얼마 남지 않았다는 경고 창이 발생하는 돌발 상황이 발생했지만 무사히 강연을 마쳤습니다.




박민근님과 저 이외에 인텔에서 두 분이 인텔의 병렬프로그래밍 관련 툴이나 라이브러리를 소개하셨습니다.


행사장에서는 Visual Studio 책자를 나누어 주고 있었고, 세미나가 끝난 후에는 제가 적은 C++0x 책도 배포되었습니다.^^


저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

  1. 오오... 성황리에 행사가 개최되었었군요. =_=

  2. 수고하셧습니다~~ ^^

    전 처음 하는 외부 세미나인지라 너무 긴장을 많이한 탓인지..
    아쉬움이 많이 남네요..흑..T^T

Posted by 흥배

C++/CLI은 네이티브 C++과 다르게 자료구조 배열을 사용하기 위해서는 array 컨테이너를 사용합니다.

array 컨테이너는 기본적으로 non-CLI 오브젝트는 사용할 수가 없습니다. 그러나 non-CLI 오브젝트가 포인터라면 사용할 수 있습니다.

 

아래는 array 컨테이너에 non-CLI 오브젝트를 사용한 경우입니다.

using namespace System;

 

class CNative

{

public:

           CNative()

           {

                     Console::WriteLine(__FUNCTION__);

           }

           ~CNative()

           {

                     Console::WriteLine(__FUNCTION__);

           }

};

 

int main(array<System::String ^> ^args)

{

           array<CNative>^ arr = gcnew array<CNative>(2);

           return 0;

}

 빌드하면 위에 이야기 했듯이 아래와 같은 빌드 에러가 발생합니다.


 

그럼 이번에는 non-CLI 오브젝트의 포인터를 사용해 보겠습니다.

#include "stdafx.h"

#include <iostream>

using namespace System;

 

class CNative

{

public:

           CNative()

           {

                     Console::WriteLine(__FUNCTION__);

           }

           ~CNative()

           {

                     Console::WriteLine(__FUNCTION__);

           }

};

 

int main(array<System::String ^> ^args)

{

           array<CNative*>^ arr = gcnew array<CNative*>(2);

           for(int i=0; i<arr->Length; i++)

           {

                     arr[i] = new CNative();

           }

 

           getchar();

           return 0;

}


이번에는 빌드에 문제가 없어서 아래와 같이 실행결과가 나옵니다.


 

그러나 위의 실행 결과를 보면 이상한 점을 발견하실 수 있을 것입니다. 그것은 CNative 오브젝트의 생성자는 호출하지만 파괴자는 호출되지 않은 것입니다. 이것은 array 컨테이너는 CLI 객체이므로 GC에서 관리하지만 non-CLI 오브젝트를 포인터 타입으로 사용한 것은 GC에서 관리하지 않으므로 만약 array GC에서 소멸 되기 전에 array에 담겨있는 non-CLI 오브젝트를 메모리(new로 할당한)를 해제하지 않으면 메모리 해제가 되지 않아서 메모리 릭이 발생합니다.

 

그래서 아래와 같이 array GC에서 소멸되기 전에 메모리를 해제하도록 해야합니다.

#include "stdafx.h"

#include <iostream>

using namespace System;

 

class CNative

{

public:

           CNative()

           {

                     Console::WriteLine(__FUNCTION__);

           }

           ~CNative()

           {

                     Console::WriteLine(__FUNCTION__);

           }

};

 

int main(array<System::String ^> ^args)

{

           array<CNative*>^ arr = gcnew array<CNative*>(2);

           for(int i=0; i<arr->Length; i++)

           {

                     arr[i] = new CNative();

           }

 

           for(int i=0; i<arr->Length; i++)

           {

                     delete arr[i];

           }

          

           getchar();

           return 0;

}

 

실행 결과


이번에는 CNative의 파괴자가 제대로 호출되고 있습니다.



출처

도서 "C++/CLI In Action"

C++/CLI를 공부하시는 분들은 "C++/CLI In Action" 책을 꼭 한번 보시기를 추천합니다.

저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

  1. 위의 실행 결과를 보면 이상한 점을 발견하실 수 있을 것입니다. 그

  2. 를 보면 이상한 점을 발견하실 수 있을 것입

  3. 과를 보면 이상한 점을 발견하실 수 있을 것입니다. 그것은 CNative 오브젝트의 생성자는 호출하지만 파괴자는 호출되지 않은 것입니다. 이것은 array 컨테이너는 CLI 객체이므로 GC에서 관리하지만 non-CLI 오브젝트를 포인터 타입으로 사용한 것

  4. 파괴자는 호출되지 않은 것입니다. 이것은 array 컨테이너는 CLI 객체이므로 GC에서 관리하지만 n

  5. 않은 것입니다. 이것은 array 컨테이

  6. 젝트를 포인터 타입으로 사용

Posted by 흥배

인터페이스는 비관리코드에서는 순수가상함수만을 가진 클래스와 같습니다. ‘interface class’라는 키워드를 사용하여 정의하면 이 클래스에는 아래와 같은 형만 멤버로 가질 수 있습니다.

 

함수

프로퍼티

이벤트

 

또한 선언만 가능하지 정의는 할 수 없습니다.

 


C++/CLI ref class C#이나 Java와 같이 다중 상속은 할 수 없지만 인터페이스를 사용하면 다중 상속(즉 인터페이스를 상속)을 할 수 있습니다.

 

interface class IA {

public:

    void funcIA();

};

interface class IB {

public:

    void funcIB();

};

interface class IC {

public:

    void funcIC();

};

ref class A {

    int i;

};

ref class B : A, IA, IB, IC {

public:

    virtual void funcIA() {   }

    virtual void funcIB() {   }

    virtual void funcIC() {   }

};

int main() {

    B^ b = gcnew B;

 

    IA^ ia = b;

    IB^ ib = b;

    IC^ ic = b;

    b->funcIA();

    ia->funcIA();

    ib->funcIB();

    ic->funcIC();

    return 0;

}

 



출처

http://cppcli.shacknet.nu/cli:interface

 

 

저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

  1. public:
    int _i;
    private:
    int i;

    b->_i;
    //b->i; // Error
    b->funcIB();
    b->funcIC();

Posted by 흥배

static 생성자

 

static 생성자는 클래스의 생성자에서 static 멤버를 초기화 하고 싶을 때 사용합니다.

ref class, value class, interface에서 사용할 수 있습니다.

 

#include "stdafx.h"

#include <iostream>

 

using namespace System;

 

ref class A {

public:

    static int a_;

    static A()

    {

        a_ += 10;

    }

};

ref class B {

public:

    static int b_;

    static B()

    {

//        a_ += 10; // error

        b_ += 10;

    }

};

ref class C {

public:

    static int c_ = 100;

    static C()

    {

        c_ = 10;

    }

};

 

int main()

{

    Console::WriteLine(A::a_);

    A::A();

    Console::WriteLine(A::a_);

 

    Console::WriteLine(B::b_);

 
    Console::WriteLine(C::c_);


     getchar();

    return 0;

}

 

< 결과 >


 

static 생성자는 런타임에서 호출하기 때문에 클래스 A의 멤버 a_는 이미 10으로 설정되어 있습니다. 그리고 이미 런타임에서 호출하였기 때문에 명시적으로 A::A()를 호출해도 실제로는 호출되지 않습니다.

 

클래스 B의 경우 static 생성자에서 비 static 멤버를 호출하면 에러가 발생합니다.

 

클래스 C의 경우 static 멤버 c_를 선언과 동시에 초기화 했지만 런타임에서 static 생성자를 호출하여 값이 10으로 설정되었습니다.

 

 

 

initonly

 

initonly로 선언된 멤버는 생성자에서만 값을 설정할 수 있습니다. 그리고 initonly static로 선언된 멤버는 static 생성자에서만 값을 설정할 수 있습니다.

 

 

ref class C
{
public:
    initonly static int x;
    initonly static int y;
    initonly int z;
    static C()
    {
        x = 1;
        y = 2;
        // z = 3; // Error
    }
    C()
    {
        // A = 2; // Error
        z = 3;
    }
    void sfunc()
    {
        // x = 5; // Error
        // z = 5; // Error
    }
};


int main()
{
    System::Console::WriteLine(C::x);
    System::Console::WriteLine(C::y);
    C c;
    System::Console::WriteLine(c.z);
    return 0;
}

 

 

 

literal

 

literal로 선언된 멤버는 선언과 동시에 값을 설정하고 이후 쓰기는 불가능합니다. 오직 읽기만 가능합니다.

using namespace System;
ref class C
{
public:
    literal String^ S = "Hello";
    literal int I = 100;
};

int main()
{
    Console::WriteLine(C::S);
    Console::WriteLine(C::I);
    return 0;
}



참고
http://cppcli.shacknet.nu/cli:static%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF
http://cppcli.shacknet.nu/cli:initonly
http://cppcli.shacknet.nu/cli:literal





저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

  1. // A = 2; // Error
    는 없습니다.

    initonly static는 선언과 동시에도 값을 설정할 수 있습니다.
    initonly static int x = 100;
    initonly static int y = 200;
    initonly int z;
    //initonly int z = 0;

    이렇게 바꾸면 이해하기 좋을 거 같습니다.
    C()
    {
    //x = 10; // Error
    //y = 20; // Error
    z = 3;
    }
    void sfunc()
    {
    //x = 5; // Error
    //y = 5; // Error
    //z = 5; // Error
    }

Posted by 흥배

비관리코드에서 로그 기능을 구현할 때 주로 가변 길이 인수를 사용합니다.

void LOG( char* szText, ... )

{

}

 


위와 같은 가변 길이 인수를 C++/CLI에서는 parameter array라는 것으로 구현합니다.

void LOG( … array<Object^>^ Values )

{

for each( Object^ value in Values )

{

   ….

}

}

 

int main()

{

LOG( 23 );

LOG( 2, 1, “error” );

 

return 0;

}

 


parameter array를 사용하면 이전 보다 안전하고, 하나의 형이 아닌 다양한 형을 인자로 받아 들일 수 있어서 유연성이 높습니다.

 

그러나 하나의 함수에서 parameter array는 하나 밖에 사용하지 못합니다. 하지만 parameter array가 아닌 형이라면 여러 개 사용할 수 있습니다. 다만 이 때는 parameter array는 가장 마지막 인수가 되어야 합니다.

 

void LOG( int nLogLevel, … array<Object^>^ Values )

{

}

 

 


참고

http://cppcli.shacknet.nu/cli:parameter_array

 

저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

'C++/CLI' 카테고리의 다른 글

[Step. 14] 인터페이스 ( interface )  (1) 2010/10/01
[Step. 15] static 생성자, initonly, literal  (1) 2010/09/24
[Step. 13] parameter array  (1) 2010/09/10
[Step. 12] for each  (1) 2010/09/03
[Step. 11] 열거형( enum )  (2) 2010/08/27
[Step. 10] 이벤트 ( event )  (0) 2010/08/20

댓글을 달아 주세요

  1. http://cppcli.shacknet.nu/cli:parameter_array
    cppcli.shacknet.nu 서버를 찾을 수 없습니다.

    ... 으로 생략된 소스코드보다 작동하는 소스코드로 예제를 설명해주시면 이해하기 좋을 거 같습니다.

    못합니다. 하지만 parameter array
    에서
    오타 하지만 p 진하게

[Step. 12] for each

C++/CLI 2010/09/03 09:00
Posted by 흥배

데이터셋에 있는 요소를 열거할 때 비관리코드에서는 보통 for문이나 while문을 자주 사용합니다.

그러나 C++/CLI에서는 for each을 사용하여 데이터셋에 있는 요소들을 열거할 수 있습니다.

for each에서 사용할 수 있는 것은 배열 이외에도 아래의 형으로 구현한 것들을 사용할 수 있습니다.

 

1. IEnumerable 인터페이스를 구현한 클래스

2. STL의 이터레이터와 같은 것을 가지고 있는 클래스

 


참고로 VC++ 8(VS 2005)에서는 비관리코드에서도 for each 문을 지원하고 있습니다.

for each를 사용할 때 주의해야 할 점은 열거하는 요소를 변경할 수는 없다는 것입니다.

 

#include "stdafx.h"

#include <iostream>

#include <vector>

#include <map>

 

using namespace std;

using namespace System;

using namespace System::Collections;

 

 

int main(array<System::String ^> ^args)

{

     // 배열

     array< int >^ Nums = { 0, 1, 2, 3, 4, 5 };

     for each(int value in Nums)

     {

          value = 2;

          Console::WriteLine( value );

     }

    // 위에서 for each 내부에서 요소의 값을 바꾸었지만 아래의 출력 값을 보면

    // 바뀌지 않은 것을 알 수 있습니다.

    for each(int value in Nums)

    {

          Console::WriteLine( value );

    }

 

   

    // 리스트

    ArrayList^ NumList = gcnew ArrayList();

    NumList->Add(1);

    NumList->Add(2);

    NumList->Add(3);

 

    for each(int value in NumList)

    {

        Console::WriteLine(value);

    }

 

 

    // vector

    vector<int> vi;

    vi.push_back(3);

    vi.push_back(4);

   

    for each(int i in vi)

    {

        Console::WriteLine(i);

    }

 

 

    // map

    map<const char*, int> num;

    num["ten"] = 10;

    num["hundred"] = 100;

 

    for each( pair<const char*, int> c in num )

    {

        Console::WriteLine(gcnew String(c.first) + c.second.ToString());

    }

 

 

    // 해쉬 테이블

    Hashtable^ ht = gcnew Hashtable();

    ht["aaa"] = "111";

    ht["bbb"] = "222";

    for each(DictionaryEntry^ dic in ht)

    {

        Console::WriteLine(dic->Key->ToString() + dic->Value->ToString());

    }

    

 

    getchar();

    return 0;

}

저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

'C++/CLI' 카테고리의 다른 글

[Step. 15] static 생성자, initonly, literal  (1) 2010/09/24
[Step. 13] parameter array  (1) 2010/09/10
[Step. 12] for each  (1) 2010/09/03
[Step. 11] 열거형( enum )  (2) 2010/08/27
[Step. 10] 이벤트 ( event )  (0) 2010/08/20
[Step. 09] 델리게이트 (delegate)  (2) 2010/08/12

댓글을 달아 주세요

  1. Hashtable^ ht는 킷값이 배열순서대로 들어가지 않는군요.
    for each(DictionaryEntry^ dic in ht)는 킷값이 거꾸로 나오는군요.

Posted by 흥배


비관리 코드의 열거형

 

비관리 코드에서 열거형을 정의할 때는 다음과 같습니다.

 

enum WEAPON_TYPE

{

GUN = 1,

SWORD = 2,

BOW = 3

};

 


열거형은 정수형으로 int 형에 대입할 수 있습니다.

int nUsedWeapon = GUN;

 

그런데 저는 위의 방식으로 사용할 때 ‘GUN’이라고 사용하기 보다는 ‘GUN’이 어떤 열거형에 속하는지 표시할 수 있도록 좀 더 다른 방식으로 사용하고 있습니다.

 

struct WEAPON

{

enum TYPE

{

GUN = 1,

SWORD = 2,

BOW = 3

};

};

 

int nUsedWeapon = WEAPON::GUN;

 

이렇게 저는 열거형을 조금 이상한 방법으로 사용하고 있는데 C++/CLI에서는 그럴 필요가 없어졌습니다. C++/CLI는 제가 딱 원하는 방식을 정식으로 지원하고 있습니다.

 


 

C++/CLI의 열거형

 

enum class WEAPON

{

   GUN = 1,

SWORD = 2,

BOW = 3

};

 

int nUsedWeapon = static_cast<int>(WEAPON::GUN);

 

C++/CLI의 열거형은 비관리코드와 비교해서 다른 점은 위에서 알 수 있듯이 암묵적으로 int 형에 대입할 수 없습니다. 왜냐하면 열거형은 정수형이 아니고 object이기 때문입니다.

그래서 캐스팅을 해야 합니다.

 

그리고 C++/CLI의 열거형은 정수형을 명시적으로 정할 수 있습니다.

enum class WEAPON : short

{

   GUN = 1,

SWORD = 2,

BOW = 3

};

 


< 추가 > - 2010. 12. 10

VC++10에서 열거형의 타입을 바로 위의 코드와 같이 명시적으로 지정해도 사용할 수가 없습니다.

enum을 사용할 때 타입 캐스팅을 해야합니다. 왜 이런지 저도 자세한 이유는 모르겠습니다.

C++/CLI에서는 enum 보다는 literal을 사용하는 것이 더 좋을 것 같다고 생각합니다.


public ref class WEAPON
{
public:
        literal short GUN = 1;
        literal short SWORD = 2;

        literal short BOW = 3;

};




참고

http://msdn.microsoft.com/ko-kr/library/ms235243.aspx

 

 

 



저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

'C++/CLI' 카테고리의 다른 글

[Step. 13] parameter array  (1) 2010/09/10
[Step. 12] for each  (1) 2010/09/03
[Step. 11] 열거형( enum )  (2) 2010/08/27
[Step. 10] 이벤트 ( event )  (0) 2010/08/20
[Step. 09] 델리게이트 (delegate)  (2) 2010/08/12
[Step. 08] 프로퍼티 ( property )  (8) 2010/08/06

댓글을 달아 주세요

  1. 비관리코드에서 NameSpace를 이용하면 struct를 쓴 것보다 더 유용하게 쓸 수 있지 않을까 싶습니다.

    namespace WEAPON
    {
    enum TYPE
    {
    GUN = 1,
    SWORD = 2,
    BOW = 3
    };
    };

    int nUsedWeapon = WEAPON::GUN;
    using namespace WEAPON;
    int nUsableWeapon = SWORD;

  2. enum을 사용할 때 타입 캐스팅을 해야 합니다. 왜 이런지 저도 자세한 이유는 모르겠습니다.

    short nUsedWeapon = (short)WEAPON::GUN;
    이렇게 사용하는 게 맞나요?

Posted by 흥배
이벤트는 그 이름처럼 이벤트를 처리할 때 사용하는 것으로 델리게이트와 조합하여 사용합니다.

보통 이벤트를 설명할 때 button 클래스를 예제로 사용하므로 저도 이것을 사용하여 간단하게 설명하겠습니다.^^

button 클래스의 여러 이벤트 중 clicked 이벤트를 구현할 때 이벤트로 불러질 클라이언트는 OnClick()이라는 멤버함수를 정의한 후 이것을 button 클래스의 clicked에 등록합니다.

 

delegate void ClickHandler();
ref class button {
public:
    event ClickHandler^ Clicked;
    button() {
        btnForTest = this;
    }
public:
    void someoneclicked() {
        Clicked();
    }
    static button^ btnForTest;
};

ref class Client {
private:
    button^ btn;
public:
    Client() {
        btn = gcnew button;
        btn->Clicked += gcnew ClickHandler(this, &Client::OnClick);
    }
private:
    void OnClick() {
        Console::WriteLine("someone clicked.");
    }
};
int main()
{
    Client^ client = gcnew Client;
   
button::btnForTest->someoneclicked();
    return 0;
}
< 출처 : http://cppcli.shacknet.nu/cli:event >
 
 
event는 몇 개의 제약이 있습니다. 
1. Clicked 호출은 button 밖에 할 수 없습니다. 
2. 클라이언트가 Clicked에 대한 조작은 += -=만 할 수 있으며 Clicked() Clicked = nullptr 같은 
것은 할 수 없습니다.
 
 
참고
http://cppcli.shacknet.nu/cli:event






저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

Posted by 흥배
델리게이트는 비관리코드에서는 함수 포인터와 같은 기능을 합니다.

 

#include <iostream>

delegate void TestDelegate();

ref class TEST

{

public:

void TestMethod()

{

  System::Console::WriteLine(“TEST::TestMethod()”);

}

};

 

int main()

{

TEST^ test = gcnew TEST();

TestDelegate^ testDelegate = gcnew TestDelegate( test, &TEST::TestMethod );

 testDelegate();


 getchar();

    return 0;

};

 

 

정적 멤버함수의 델리게이트

 

#include <iostream>

 delegate void TestDelegate();

 ref class TEST

{

public:

static void TestMethod()

{

  System::Console::WriteLine(“TEST::TestMethod()”);

}

};

 

int main()

{

TestDelegate^ testDelegate = gcnew TestDelegate( &TEST::TestMethod );

 

testDelegate();

 

getchar();

return 0;

};

 

 

복수 개의 델리게이트

 

델리게이트는 하나가 아닌 여러 개를 설정할 있습니다.

 

#include <iostream>

delegate void TestDelegate();

 

ref class TESTA

{

public:

void TestMethod()

{

  System::Console::WriteLine(“TESTA::TestMethod()”);

}

};

 

ref class TESTB

{

public:

static void TestMethod()

{

  System::Console::WriteLine(“TESTB::TestMethod()”);

}

};

 

ref class TESTC

{

public:

void operator()()

{

  System::Console::WriteLine(“TESTC::operator()”);

}

};

 

int main()

{

TestDelegate^ testDelegate;

TESTA testA;

TESTC testC;

 

testDelegate = gcnew TestDelegate( testA, &TESTA::TestMethod );

testDelegate += gcnew TestDelegate(&TESTB::TestMethod );

testDelegate += gcnew TestDelegate( testC, &TESTC::operator );

 

testDelegate();

 

getchar();

return 0;

};

 

 

델리게이트의 비교와 삭제

 ==으로 델리게이트를 비교하면 이것은 핸들의 비교가 아닌 델리게이트가 가지고 있는 함수를 비교하는 것입니다. -=을 사용하여 설정한 델리게이트를 제거할 수도 있습니다.

using namespace System;

delegate void MyDele(int);


void func1(int i)

{

    Console::WriteLine("func1");

}


void func2(int j)

{

    Console::WriteLine("func2");

}


int main()

{

    MyDele^ dele;

    dele += gcnew MyDele(&func1);

    dele += gcnew MyDele(&func2);

    MyDele^ dele2 = gcnew MyDele(func1);

    dele2 += gcnew MyDele(&func2);

    if ( dele == dele2 )  {

        Console::WriteLine("TRUE");

    } else {

        Console::WriteLine("FALSE");

    }

   

    dele -= gcnew MyDele(&func1); 

   

    dele(1); 

   

   return 0;

}

< 예제 출처 : http://cppcli.shacknet.nu/cli:delegate >

 

위의 예의 델리게이트들은 모두 void를 반환하고 파라미터가 없는 것인데 당연하듯이 반환 값이나 파라미터를 가질 수 있습니다.




델리게이트의 비동기 실행

 

델리게이트는 비동기 실행을 지원합니다. 비동기 실행은 처리를 요청한 후 종료를 기다리지 않은 호출한 곳으로 제어를 넘겨줍니다. 델리게이트 함수가 긴 시간을 필요로 하는 작업인 경우 비동기 실행을 이용하면 프로그램의 응답성을 높일 수 있습니다.

 

델리게이트의 비동기 실행은 스레드를 사용합니다. 이런 경우 비동기 실행을 할 때마다 스레드의 생성과 소멸에 부담을 느낄 수도 있지만 델리게이트는 닷넷의 기능을 잘 활용하여 스레드를 생성/삭제하지 않고 스레드 풀에 있는 스레드를 사용하므로 스레드 사용에 대한 부담이 작습니다.

 

비동기 실행을 할 때는 주의해야 할 점이 있습니다. 비동기 실행을 하는 경우 델리게이트에는 꼭 하나의 함수만 등록해야 합니다. 만약 2개 이상 등록하였다면 예외가 발생합니다.

 

비동기 실행은 BeginInvoke()를 사용하고, 만약 종료를 기다리고 싶다면 EndInvoke()를 사용합니다.

 

#include "stdafx.h"

#include <iostream>

 

using namespace System;

 

delegate void MyDele(void);

 

void myfunc(void)

{

    System::Threading::Thread::Sleep(3000);

}

 

 

int main(array<System::String ^> ^args)

{

     MyDele^ dele = gcnew MyDele(&myfunc);

            Console::WriteLine(L"1");

     IAsyncResult^ result = dele->BeginInvoke(nullptr,nullptr);

            Console::WriteLine(L"2");

    dele->EndInvoke(result);

            Console::WriteLine(L"3");

   

    getchar();

    return 0;

}

 

위 코드를 실행하면 '2'가 찍힌 이후 3초가 지난 이후에 3이 찍힙니다.





참고
http://cppcli.shacknet.nu/cli:delegate
http://cppcli.shacknet.nu/cli:delegate%E3%81%9D%E3%81%AE2



저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

  1. delegate void TetsDelegate();
    delegate void TestDelegate();
    오타
    Tets->Test

  2. 흥배님 맨 위에서 아래로 소스코드 3개가 빌드에러 납니다.
    1. 델리게이트는 비관리코드에서는 함수 포인터와 같은 기능을 합니다.
    2. 정적 멤버함수의 델리게이트
    3. 복수 개의 델리게이트

    델리게이트의 비교와 삭제는 아래처럼 주석처리 해야 작동합니다. 도와주세요.
    using namespace System;

    delegate void MyDele(int);

    void func1(int i)
    {
    Console::WriteLine("func1";);
    }

    void func2(int j)
    {
    Console::WriteLine("func2";);
    }

    int main()
    {
    MyDele^ dele;
    dele += gcnew MyDele(&func1);
    dele += gcnew MyDele(&func2);
    //MyDele^ dele2 = gcnew MyDele(func1());
    //dele2 += gcnew MyDele(&func2);
    //if (dele == dele2)
    //{
    // Console::WriteLine("TRUE";);
    //}
    //else
    //{
    // Console::WriteLine("FALSE";);
    //}

    dele -= gcnew MyDele(&func1);

    dele(1);

    return 0;
    }

Posted by 흥배

보통 비관리 클래스를 정의할 때 캡슐화를 위해서 멤버 변수는 최대한 private 접근으로 한 후 외부에서의 접근을 위해서 get set 멤버 함수를 정의합니다.

 

class Character

{

public:

…….

   void SetCharCd( const int nCharCd ) { m_nCharCd = nCharCd; }

   int GetCharCd() { return m_nCharCd; }

…….

private:

   int m_nCharCd;

   …….

};

 


클래스의 멤버를 하나 정의할 때마다 그에 대응하는 get, set 멤버 함수를 정의하는 것은 좀 귀찮은 일이기도 합니다. 그래서 관리코드에서는 이 작업을 쉽게 해주는 property가 생겼습니다.

 

ref class Character

{

public:

…….

    property int CharCd

{

   void set( int nCharCd ) { m_nCharCd = nCharCd; }

   int get() { return m_nCharCd; }

}  

…….

private:

   int m_nCharCd;

   …….

};

 

위 코드에서는 get set을 둘 다 정의 했는데 둘 중 하나만 정의 해도 괜찮습니다.

또 위의 set은 아주 간단하게 그냥 대입만 하고 있는데 좀 더 로직을 넣을 수도 있습니다.

 

ref class Character

{

public:

…….

    property int CharCd

{

   void set( int nCharCd )

{

  if( nCharCd < 0 ) {

     m_nCharCd = 0;

  } else {

     m_nCharCd = nCharCd;

  }

}

 

   int get() { return m_nCharCd; }

}  

…….

private:

   int m_nCharCd;

   …….

};

 

 


property 선언과 정의 나누기


일반적으로 클래스의 멤버 선언은 헤더 파일에 정의는 cpp 파일에 하듯이 property도 선언과 정의를 나눌 수 있습니다.

 

ref class Character

{

public:

…….

    property int CharCd

{

   void set( int nCharCd );

   int get();

}  

…….

private:

   int m_nCharCd;

   …….

};

 

 

void Character::CharCd::set( int nCharCd )

{

if( nCharCd < 0 ) {

m_nCharCd = 0;

} else {

   m_nCharCd = nCharCd;

  }

}

 

void Character::CharCd::get()

{

return m_nCharCd;

}

 



 

get set의 접근 지정자 다르게 하기

 

위에서 property를 정의할 때 get set은 모두 public 였습니다.

이것을 각각 다르게 접근 지정자를 정할 수 있습니다.

 

ref class Character

{

public:

…….

    property int CharCd

{

protected:

   void set( int nCharCd )

{

  if( nCharCd < 0 ) {

     m_nCharCd = 0;

  } else {

     m_nCharCd = nCharCd;

  }

}

 

    public:

   int get() { return m_nCharCd; }

}  

…….

private:

   int m_nCharCd;

   …….

};

 

 

 

 

참고

http://cppcli.shacknet.nu/cli:property

http://vene.wankuma.com/prog/CppCli_Property.aspx

 

 

저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

  1. C++ CLI 문법이 정말 많이 좋아지고 있군요 ㅎㅎ

    • 공돌이 2010/08/06 18:23

      C#도 해당사항이 되나요?

    • 네. C#도 해당되는 내용입니다. 다만, 언제든지 getter의 접근 제한자가 setter보다는 넓어야 한다는 제약이 붙습니다.

      //C#의 경우
      public int Test
      {
      get { ... } // public
      private set { ... } // private
      }

  2. C++/CLI 공부를 해보면 좀 애매한면이 있지만 요즘 시대에 맞는 기능이 꽤 많아서 MS의 새로운 C++ 표준이라는 생각이 들기도 합니다. 아마 MS가 단독으로 새로운 C++ 표준을 만든다면 지금의 C++/CLI와 비슷한 모습이 될 것 같습니다(참고로 C++/CLI는 꼭 닷넷을 위해 만들어진 언어가 아닙니다).

  3. 아, 그리고 이건 개인적인 호기심인데, C#이나 VB.NET의 경우는 이벤트 프로퍼티에 대해서도 Custom Override를 지원하는데, C++ CLI도 이에 대응되는 문법 체계가 동일하게 존재하는지 궁금하네요. :-)

    //C#의 경우
    public event EventHandler MyEvent
    {
    add { ... }
    remove { ... }
    }

  4. property 선언과 정의 나누기

    ref class Character { ... }
    가 *.h 파일에 선언되고

    void Character::CharCd::set( int CharCd ) { ... }
    void Character::CharCd::get() { ... }
    가 *.cpp 파일에 정의되는 건가요?

  5. public:
    ...
    private:
    ...
    글에 보면 이렇게 되어 있는데 public:과 private:는 같은 이름의 클래스에 들어 있는 건가요?

  6. property 선언과 정의 나누기
    void Character::CharCd::set( int CharCd ) 오타입니다.
    void Character::CharCd::set( int nCharCd )로 고쳐야 합니다.