• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            flash

            posted @ 2010-06-25 17:43 莫失莫忘 閱讀(95) | 評論 (0)編輯 收藏

            第一章 基礎

            初始化

            SDL由八個子系統組成——音頻、CDROM、事件處理、文件I/O、游戲桿、線程、記時器和視頻。使用前必須調用SDL_Init或 SDL_InitSubSystem初始化。SDL_Init必須早于其他所有SDL調用,它將自動初始化事件處理、文件I/O和線程子系統,并根據參數 選擇啟動其他子系統。例如,初始化缺省和視頻子系統:

            SDL_Init(SDL_INIT_VIDEO);初始化缺省、視頻和記時器子系統:

            SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);SDL_Init對應SDL_Quit(和SDL_QuitSubSystem)。SDL_Quit關閉所有子系統,必須在程序關閉前調用。

            除此之外,我們還必須進行錯誤處理。很多SDL函數返回一個值指示成功與否。例如SDL_Init失敗時返回-1。每當SDL出錯時,錯誤信息被保存,并可用SDL_GetError取得。

            例1-1 初始化SDL

            #include "SDL.h" /* All SDL App's need this */

            #include <stdio.h>

            int main() {

            printf("Initializing SDL.\n");

            /* Initialize defaults, Video and Audio */

            if((SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO)==-1)) {

            printf("Could not initialize SDL: %s.\n", SDL_GetError());

            exit(-1);

            }

            printf("SDL initialized.\n");

            printf("Quiting SDL.\n");

            /* Shutdown all subsystems */

            SDL_Quit();

            printf("Quiting....\n");

            exit(0);

            }

            第二章 圖像和視頻

            SDL Vidow顯示

            初始化SDL Video顯示

            視頻是最常用的部分,也是SDL最完整的子系統。下面的初始化過程是每個SDL程序都要做的,即使可能有些不同。

            例2-1 初始化視頻

            SDL_Surface *screen;

            /* Initialize the SDL library */

            if( SDL_Init(SDL_INIT_VIDEO) < 0 ) {

            fprintf(stderr,

            "Couldn't initialize SDL: %s\n", SDL_GetError());

            exit(1);

            }

            /* Clean up on exit */

            atexit(SDL_Quit);

            /*

            * Initialize the display in a 640x480 8-bit palettized mode,

            * requesting a software surface

            */

            screen = SDL_SetVideoMode(640, 480, 8, SDL_SWSURFACE);

            if ( screen == NULL ) {

            fprintf(stderr, "Couldn't set 640x480x8 video mode: %s\n",

            SDL_GetError());

            exit(1);

            }

            初始化最佳視頻模式

            如果你希望某種色深(顏色數)但如果用戶的顯示器不支持也可以接受其他色深,使用加SDL_ANYFORMAT參數的SDL_SetVideoMode。您還可以用SDL_VideoModeOK來找到與請求模式最接近的模式。

            例2-2 初始化最佳視頻模式

            /* Have a preference for 8-bit, but accept any depth */

            screen = SDL_SetVideoMode(640, 480, 8, SDL_SWSURFACE|SDL_ANYFORMAT);

            if ( screen == NULL ) {

            fprintf(stderr, "Couldn't set 640x480x8 video mode: %s\n",

            SDL_GetError());

            exit(1);

            }

            printf("Set 640x480 at %d bits-per-pixel mode\n",

            screen->format->BitsPerPixel);

            讀取并顯示BMP文件

            當SDL已經初始化,視頻模式已經選擇,下面的函數將讀取并顯示指定的BMP文件。

            例2-3 讀取并顯示BMP文件

            void display_bmp(char *file_name)

            {

            SDL_Surface *image;

            /* Load the BMP file into a surface */

            image = SDL_LoadBMP(file_name);

            if (image == NULL) {

            fprintf(stderr, "Couldn't load %s: %s\n", file_name, SDL_GetError());

            return;

            }

            /*

            * Palettized screen modes will have a default palette (a standard

            * 8*8*4 colour cube), but if the image is palettized as well we can

            * use that palette for a nicer colour matching

            */

            if (image->format->palette && screen->format->palette) {

            SDL_SetColors(screen, image->format->palette->colors, 0,

            image->format->palette->ncolors);

            }

            /* Blit onto the screen surface */

            if(SDL_BlitSurface(image, NULL, screen, NULL) < 0)

            fprintf(stderr, "BlitSurface error: %s\n", SDL_GetError());

            SDL_UpdateRect(screen, 0, 0, image->w, image->h);

            /* Free the allocated BMP surface */

            SDL_FreeSurface(image);

            }

            直接在顯示上繪圖

            下面兩個函數實現在圖像平面的像素讀寫。它們被細心設計成可以用于所有色深。記住在使用前要先鎖定圖像平面,之后要解鎖。

            在像素值和其紅、綠、藍值間轉換,使用SDL_GetRGB()和SDL_MapRGB()。

            例2-4 getpixel()

            /*

            * Return the pixel value at (x, y)

            * NOTE: The surface must be locked before calling this!

            */

            Uint32 getpixel(SDL_Surface *surface, int x, int y)

            {

            int bpp = surface->format->BytesPerPixel;

            /* Here p is the address to the pixel we want to retrieve */

            Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;

            switch(bpp) {

            case 1:

            return *p;

            case 2:

            return *(Uint16 *)p;

            case 3:

            if(SDL_BYTEORDER == SDL_BIG_ENDIAN)

            return p[0] << 16 | p[1] << 8 | p[2];

            else

            return p[0] | p[1] << 8 | p[2] << 16;

            case 4:

            return *(Uint32 *)p;

            default:

            return 0; /* shouldn't happen, but avoids warnings */

            }

            }

            例2-5 putpixel()

            /*

            * Set the pixel at (x, y) to the given value

            * NOTE: The surface must be locked before calling this!

            */

            void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)

            {

            int bpp = surface->format->BytesPerPixel;

            /* Here p is the address to the pixel we want to set */

            Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;

            switch(bpp) {

            case 1:

            *p = pixel;

            break;

            case 2:

            *(Uint16 *)p = pixel;

            break;

            case 3:

            if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {

            p[0] = (pixel >> 16) & 0xff;

            p[1] = (pixel >> 8) & 0xff;

            p[2] = pixel & 0xff;

            } else {

            p[0] = pixel & 0xff;

            p[1] = (pixel >> 8) & 0xff;

            p[2] = (pixel >> 16) & 0xff;

            }

            break;

            case 4:

            *(Uint32 *)p = pixel;

            break;

            }

            }

            例2-6 使用上面的putpixel()在屏幕中心畫一個黃點

            /* Code to set a yellow pixel at the center of the screen */

            int x, y;

            Uint32 yellow;

            /* Map the color yellow to this display (R=0xff, G=0xFF, B=0x00)

            Note: If the display is palettized, you must set the palette first.

            */

            yellow = SDL_MapRGB(screen->format, 0xff, 0xff, 0x00);

            x = screen->w / 2;

            y = screen->h / 2;

            /* Lock the screen for direct access to the pixels */

            if ( SDL_MUSTLOCK(screen) ) {

            if ( SDL_LockSurface(screen) < 0 ) {

            fprintf(stderr, "Can't lock screen: %s\n", SDL_GetError());

            return;

            }

            }

            putpixel(screen, x, y, yellow);

            if ( SDL_MUSTLOCK(screen) ) {

            SDL_UnlockSurface(screen);

            }

            /* Update just the part of the display that we've changed */

            SDL_UpdateRect(screen, x, y, 1, 1);

            return;


            并用SDL和OpenGL

            SDL可以在多種平臺(Linux/X11, Win32, BeOS, MacOS Classic/Toolbox, MacOS X, FreeBSD/X11 and Solaris/X11)上創建和使用OpenGL上下文。這允許你在OpenGL程序中使用SDL的音頻、事件、線程和記時器,而這些通常是GLUT的任務。

            初始化

            和普通的初始化類似,但有三點不同:必須傳SDL_OPENGL參數給SDL_SetVideoMode;必須使用SDL_GL_SetAttribute指定一些GL屬性(深度緩沖區位寬,幀緩沖位寬等);如果您想使用雙緩沖,必須作為GL屬性指定

            例2-7 初始化SDL加OpenGL

            /* Information about the current video settings. */

            const SDL_VideoInfo* info = NULL;

            /* Dimensions of our window. */

            int width = 0;

            int height = 0;

            /* Color depth in bits of our window. */

            int bpp = 0;

            /* Flags we will pass into SDL_SetVideoMode. */

            int flags = 0;

            /* First, initialize SDL's video subsystem. */

            if( SDL_Init( SDL_INIT_VIDEO ) < 0 ) {

            /* Failed, exit. */

            fprintf( stderr, "Video initialization failed: %s\n",

            SDL_GetError( ) );

            quit_tutorial( 1 );

            }

            /* Let's get some video information. */

            info = SDL_GetVideoInfo( );

            if( !info ) {

            /* This should probably never happen. */

            fprintf( stderr, "Video query failed: %s\n",

            SDL_GetError( ) );

            quit_tutorial( 1 );

            }

            /*

            * Set our width/height to 640/480 (you would

            * of course let the user decide this in a normal

            * app). We get the bpp we will request from

            * the display. On X11, VidMode can't change

            * resolution, so this is probably being overly

            * safe. Under Win32, ChangeDisplaySettings

            * can change the bpp.

            */

            width = 640;

            height = 480;

            bpp = info->vfmt->BitsPerPixel;

            /*

            * Now, we want to setup our requested

            * window attributes for our OpenGL window.

            * We want *at least* 5 bits of red, green

            * and blue. We also want at least a 16-bit

            * depth buffer.

            *

            * The last thing we do is request a double

            * buffered window. '1' turns on double

            * buffering, '0' turns it off.

            *

            * Note that we do not use SDL_DOUBLEBUF in

            * the flags to SDL_SetVideoMode. That does

            * not affect the GL attribute state, only

            * the standard 2D blitting setup.

            */

            SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 );

            SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 );

            SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 );

            SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );

            SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );

            /*

            * We want to request that SDL provide us

            * with an OpenGL window, in a fullscreen

            * video mode.

            *

            * EXERCISE:

            * Make starting windowed an option, and

            * handle the resize events properly with

            * glViewport.

            */

            flags = SDL_OPENGL | SDL_FULLSCREEN;

            /*

            * Set the video mode

            */

            if( SDL_SetVideoMode( width, height, bpp, flags ) == 0 ) {

            /*

            * This could happen for a variety of reasons,

            * including DISPLAY not being set, the specified

            * resolution not being available, etc.

            */

            fprintf( stderr, "Video mode set failed: %s\n",

            SDL_GetError( ) );

            quit_tutorial( 1 );

            }

            posted @ 2010-06-11 17:00 莫失莫忘 閱讀(541) | 評論 (0)編輯 收藏

              顯然DirectDraw是Windows下寫2D圖形程序的最好選擇,雖然Direct3D也可以寫,但是沒DirectDraw簡單方便,特別對于初學者,一來就接觸那么多函數和參數總不是件愉快的事,所以我的文章主要結合我做的工作,談談DirectDraw編程中一些比較關鍵的技術,大多是我自己想出來的。我想先聲明,我的文章可以任意轉載,源代碼可以任意使用和修改。

              由于我是業余時間寫的文章,所以只能每次發表一篇,希望我的工作可以為大家的游戲增光添彩,同時我的文章主要面向有基本C++,DirectDraw,匯編和MMX編程經驗的朋友,如果你對這些了解不夠,請先學習一下再閱讀。也歡迎大家和我交流,我的QQ是35830152,EMAIL:EUHO@SINA.COM。

              作為第一篇,我想先談談Alpha混合的問題。這里32位色的圖形模式我們不考慮,因為技巧并不多,占用顯存和內存大,實際應用的也不多。我們把焦點放在16位色的模式上。我們把源點C2和Alpha通道點C1用Alpha混合,混合后得到點C,如果Alpha取0~1,公式如下:

            C = C2*Alpha + C1*(1-Alpha)

            如果Alpha取0~32,公式如下:

            C = (C2*Alpha + C1*(1-Alpha))>>5

            每個點由R,G,B 3個分量組成,所以上面的運算要分別對每個分量進行計算,如果整體計算,由于進位的關系我們會得到錯誤的結果。我們只考慮用得較多的565格式,即16位的顏色值為RRRRRGGGGGGBBBBB,555格式原理是一樣的。顯然我們每次處理一個點似乎只能按照“拆分-分別運算-拆分”來寫代碼,但是這樣是低效的,想想1024*768模式下運算一幀要進行多少次運算,一定快不到哪里去。

              Intel有段很長的代碼,我沒仔細看,也沒試驗,總覺得不太可靠(呵呵)。還看了GameRes上的一些相關文章,還是有值得參考的地方,就是覺得看了還是有些茫然。

              下面說我的算法,首先說明這個快速算法是針對每個Alpha值建立一個函數進行運算,如果在一個函數里實現任意Alpha的運算,一次只能運算2個點,而且匯編代碼是26行,而且有2次乘法,也用到了部分MMX加速。經過針對每一級Alpha的優化處理,每次處理4個點,代碼只要8行左右,移位代替了乘法運算,完全發揮了MMX的威力。我只做了17級變換,0級和17級不用做,1到15原理一樣,只有少少的不同,現在我舉例半透明的算法,其他大家可以自己實現,有問題也可以和我交流。

              Alpha運算中每個點3個色素,每個色素都要按上面那個公式運算,也就是每個色素要做2次乘法和一次加發,盡管可以變換一下不做浮點運算,但性能又能提高多少?我先講一下我算法的一個基本原理,即“任意分組移位”,意思就是把一個數中分為N組,每組位數并不要求相同,我們用一次移位和一次與運算就能做到好像是每個分組移位而互不影響的效果。比半透明下Alpha=0.5,換成移位就是>>1,我們先把C右移一位,然后AND 一個2進制的數0111101111101111(0x7BEF),就完成了3個色素同時*0.5的運算,簡單吧。

              代碼相信大家很容易就看懂了,大家把匯編部分和自己的程序結合就可以了,只要提供一些參數,比如頁面數據指針和長度高度等資料.下次我會發布帶Colorkey和Clip功能的代碼,同樣是MMX處理的,而且不用if(這會大大降低流水線的效率).以后還會介紹動態光源,灰度圖,動畫控制等高級主題,歡迎大家指導,由于水平和打字原因,可能文章中會有錯誤,請諒解.

            下面是任意Alpha的混合運算

            BOOL
            CAresMaterial::DrawAlpha( LONG X, LONG Y, LPRECT pRect, BYTE Alpha )
            {
                unsigned __int16 *pSrc, *pDest;
               
            unsigned __int32 A, PA;
               
            unsigned __int16 Width, Height;
               
            unsigned __int32 D1, D2;
               
            RECT Rect;

               
            A = Alpha & 0x1F;
               
            PA = 0x1F - A;
               
            Width = (unsigned __int16)(pRect->right - pRect->left + 1);
               
            Height = (unsigned __int16)(pRect->bottom - pRect->top + 1);
               
            D1 = (m_Desc.dwPitch - Width + 1)<<1 ;
               
            D2 = (m_Desc.pAres->GetScreenPitch() - Width + 1)<<1 ;
               
            SetRect( &Rect, X, Y, X+Width-1, Y+Height-1 );
               
            m_Desc.pAres->BackToDILayer( &Rect );
               
            pSrc = m_Desc.pData + pRect->top*m_Desc.dwPitch + pRect->left;
               
            pDest = m_Desc.pAres->GetDILayerData() + Y*m_Desc.pAres->GetScreenPitch() + X;


               
            __asm
               
            {
               
               
            mov esi,pSrc
               
               
            mov edi,pDest
               
               
            movd mm2,A
               
               
            movd mm3,PA

               
               
            mov cx,Height
               
               
            shl ecx,16
               
               
            mov cx,Width

               
            LOOPA:
               
               
            ror ecx,16
               
               
            dec cx
               
               
            jz DONE
               
               
            ror ecx,16

               
            LOOPB:
               
               
            dec cx
               
               
            jz NEXTLINE
               
               
            //Process one point
               
               
            mov ax,[esi]
               
               
            mov dx,ax
               
               
            shl eax,16
               
               
            mov ax,dx
               
               
            and eax,0x7E0F81F
               
               
            movd edx,mm2
               
               
            mul edx
               
               
            movd mm0,eax

               
               
            mov ax,[edi]
               
               
            mov dx,ax
               
               
            shl eax,16
               
               
            mov ax,dx
               
               
            and eax,0x7E0F81F
               
               
            movd edx,mm3
               
               
            mul edx
               
               
            movd mm1,eax

               
               
            paddd mm0,mm1
               
               
            psrlq mm0,5
               
               
            movd eax,mm0
               
               
            and eax,0x7E0F81F
               
               
            mov edx,eax
               
               
            shr edx,16
               
               
            or eax,edx
               
               
            mov [edi],ax

               
               
            inc esi
               
               
            inc edi
               
               
            inc esi
               
               
            inc edi
               
               
            jmp LOOPB

               
            NEXTLINE:
               
               
            add esi,D1
               
               
            add edi,D2
               
               
            mov cx,Width
               
               
            jmp LOOPA

               
            DONE:
               
               
            emms
               
            }

               
            m_Desc.pAres->DILayerToBack( &Rect );

               
            return TRUE;
            }



            下面是半透明Alpha的混合運算

            void
            CAresMaterial::DrawAlpha1( LONG X, LONG Y, LPRECT pRect )
            {

                unsigned __int16 *pSrc, *pDest;
                unsigned __int16 Width, Height, DW, DLeft;
                unsigned __int32 D1, D2;
                static unsigned __int64 MASKER = 0x7BEF7BEF7BEF7BEF;
                RECT Rect;

                Width = (unsigned __int16)(pRect->right - pRect->left);
                Height = (unsigned __int16)(pRect->bottom - pRect->top + 1 );
                pSrc = m_Desc.pData + pRect->top*m_Desc.dwPitch + pRect->left;
                pDest = m_Desc.pAres->GetBackData() + Y*m_Desc.pAres->GetScreenPitch() + X;

                DLeft = (Width % 4) + 1;
                DW = (Width>>2) + 1;

                D1 = (m_Desc.dwPitch - Width)<<1 ;
                D2 = (m_Desc.pAres->GetScreenPitch() - Width)<<1 ;
                SetRect( &Rect, X, Y, X+Width, Y+Height-1 );

                __asm
                {
                    mov esi,pSrc
                    mov edi,pDest
                    mov bx,DLeft

                    mov cx,Height
                    shl ecx,16
                    mov cx,DW

                LOOPA:
                    ror ecx,16
                    dec cx
                    jz DONE
                    ror ecx,16

                LOOPB:
                    dec cx
                    jz ENDLINE
                    //Process four points once
                    movq mm0,[esi]
                    movq mm1,[edi]
                    psrlq mm0,1
                    psrlq mm1,1
                    pand mm0,MASKER
                    pand mm1,MASKER
                    paddw mm0,mm1
                    movq [edi],mm0

                    add esi,8
                    add edi,8
                    jmp LOOPB

                ENDLINE:
                    dec bx
                    jz NEXTLINE
                    mov ax,[esi]
                    mov dx,[edi]
                    shr ax,1
                    shr dx,1
                    and ax,0x7BEF
                    and dx,0x7BEF
                    add ax,dx
                    mov [edi],ax
                    inc esi
                    inc esi
                    inc edi
                    inc edi
                    jmp ENDLINE

                NEXTLINE:
                    add esi,D1
                    add edi,D2
                    mov cx,DW
                    mov bx,DLeft
                    jmp LOOPA

                DONE:
                    emms
                }
            }

            posted @ 2010-06-09 14:34 莫失莫忘 閱讀(233) | 評論 (0)編輯 收藏

            http://dev.csdn.net/htmls/42/42883.html
            http://www.vckbase.com/document/viewdoc/?id=1440
            http://g.csdn.net/5143319
            http://d.download.csdn.net/down/889596/xuezhimeng
            http://www.pconline.com.cn/download/heji/0901/1549110_1.html
            http://cache.baidu.com/c?m=9d78d513d98401ae4fece4697b16c0126f43f1662ba0d4013894cd47c9221d03506790a63a644b5383966b6776ff1a07bcb7217240527de8869c9f4ba9e2da3f2efe223f701b854511d918&p=8c70c64ad4934eae13f1c9214e&user=baidu
            http://tieba.baidu.com/f?kz=714213830
            http://cache.baidu.com/c?m=9d78d513d9d437ae4f9ce3697c62c0161c4381132ba7a4020bd48438e2732d305321a3e52878564291d27d141cb20c19afe73605754476eb8cc8ff1b80e48f7e72cd7b6a2d4fd00012d01cb28a1b628171c70bb4f94efaffab6ec5f39792c208048c16583ad9eddd0d46479131f31631e2a59f49025f67e0ab6f3b&p=c6769a45c5d917ff57eb9435455f&user=baidu
            http://www.baidu.com/s?tn=16site_5_pg&bs=%D3%CE%CF%B7%BC%DC%B9%B9&f=8&wd=%D3%CE%CF%B7%BF%F2%BC%DC
            http://www.pudn.com/downloads217/sourcecode/windows/network/detail1023143.html
            碰撞檢測:
            http://dev.gameres.com/Program/Visual/3D/3DCollision.mht
            http://wenku.baidu.com/view/c317e65c3b3567ec102d8a58.html
            http://tieba.baidu.com/f?kw=%D0%C7%BC%CA%B9%A4%D7%F7%CA%D2
            2D碰撞檢測引擎(相關文章):
            http://www.baidu.com/s?bs=Irrlicht+%C5%F6%D7%B2%BC%EC%B2%E2&f=8&wd=Irrlicht+2D%C5%F6%D7%B2%BC%EC%B2%E2
            http://blog.csdn.net/aladins/archive/2007/01/14/1482595.aspx
            http://www.baidu.com/s?wd=SDL%C5%F6%D7%B2%BC%EC%B2%E2
            http://www.verycd.com/files/955e419766a2ed8672472f3ce4180c8c22445512
            SDL:
            http://cache.baidu.com/c?m=9f65cb4a8c8507ed4fece763105392230e54f729778693027fa3cf1fd5790f1c0721bca66178505380936b6777ac4257e0fb3565377523a09bbe8b5dddccc86e70d633712d5cd04e538547b8ca3632b02a872d99b868e6ad813584afa2c4af5544be54120a80e7fb2c&p=8b2a9503cc934eae52bacd3e510c&user=baidu
            http://wenku.baidu.com/view/5ecb3b0cba1aa8114431d91b.html
            關于游戲編程的一些其他的東西
            http://www.fish888.com/Quake2-MD2-t172272
            http://zhidao.baidu.com/question/5641067.html
            http://bbs.gameres.com/showthread.asp?threadid=147168
            http://www.baidu.com/s?wd=C%D3%CE%CF%B7%B1%E0%B3%CC%B4%D3%C8%EB%C3%C5%B5%BD%BE%AB%CD%A8
            http://dev.gameres.com/Program/Abstract/Thinking/RLE.htm
            http://www.baidu.com/s?bs=2D%D3%CE%CF%B7+%C5%F6%D7%B2%BC%EC%B2%E2%BF%E2&f=8&wd=%D3%CE%CF%B7+%C5%F6%D7%B2%BC%EC%B2%E2%BF%E2
            模擬城市的源代碼
            http://resource.gameres.com/simcity_source.zip

            如果這個沒有刷出來就用關鍵字:用SDL打造我們自己的戰棋游戲。

              通過運行時類型識別(RTTI)(Run-Time Type Information),程序能夠使用基類的指針或引用來檢查這些指針或引用所指的對象的實際派生類型。   RTTI提供了一下兩個非常有用的操作符:   (1)typeid操作符,返回指針和引用所指的實際類型;   (2)dynamic_cast操作符,將基類類型的指針或引用安全地轉換為派生類型的指針或引用。   面向對象的編程語言,象C++,Java,delphi都提供了對RTTI的支持。 本文將簡略介紹 RTTI 的一些背景知識、描述 RTTI 的概念,并通過具體例子和代碼介紹什么時候使用以及如何使用 RTTI;本文還將詳細描述兩個重要的 RTTI 運算符的使用方法,它們是 typeid 和 dynamic_cast。   其實,RTTI 在C++中并不是什么新的東西,它早在十多年以前就已經出現了。但是大多數開發人員,包括許多高層次的C++程序員對它并不怎么熟悉,更不用說使用 RTTI 來設計和編寫應用程序了。   一些面向對象專家在傳播自己的設計理念時,大多都主張在設計和開發中明智地使用虛擬成員函數,而不用 RTTI 機制。但是,在很多情況下,虛擬函數無法克服本身的局限。每每涉及到處理異類容器和根基類層次(如 MFC)時,不可避免要對對象類型進行動態判斷,也就是動態類型的偵測。如何確定對象的動態類型呢?答案是使用內建的 RTTI 中的運算符:typeid 和 dynamic_cast。   在C++中存在虛函數,也就存在了多態性,對于多態性的對象,在程序編譯時可能會出現無法確定對象的類型的情況。當類中含有虛函數時,其基類的指針就可以指向任何派生類的對象,這時就有可能不知道基類指針到底指向的是哪個對象的情況,類型的確定要在運行時利用運行時類型標識做出。為了獲得一個對象的類型可以使用typeid函數,該函數反回一個對type_info類對象的引用,要使用typeid必須使用頭文件<typeinfo>,因為typeid是一個反回類型為typ_info的引用的函數所以這里有必要先介紹一下type_info類    1、typid函數:該函數的主要作用就是讓用戶知道當前的變量是什么類型的,比如使用typid(a).name()就能知道變量a是什么類型的。因為typid()函數是一個反回類型為typid_info類型的函數,所以下面先對type_info類作下介紹   2、type_info類:該類的具體實現方式依編譯器而定,但一般都有如下的成員定義   class type_info   {private:   type_info(const type_info &);   type_info& operator =(const type_info&); //type_info類的復制構造函數和賦值運算符是私有的。   public:   virtual ~type_info(); //析構函數   bool operator = =(const type_info&) const; //在type_info類中重載了= =運算符,該運算符可以比較兩個對象的類型是否相等。   bool operator !=(const type_info&)const; //重載的!=運算符,以比較兩個對象的類型是否不相等   const char * name() const; //使用得較多的成員函數name,該函數反回對象的類型的名字。前面使用的typeid(a).name()就調用了該成員函數   bool before(const type_info&);};   因為type_info類的復制構造函數和賦值運算符都是私有的,所以不允許用戶自已創建type_info的類,比如type_info A;錯誤,沒有默認的構造函數。唯一要使用type_info類的方法就是使用typeid函數。   3、typeid函數怎樣創建type_info類的對象:該函數反回type_info類對象的引用,即形式為type_info& typid();因此也可以說typid函數是type_info類的一個引用對象,可以訪問type_info類的成員。但因為不能創建type_info類的對象,而typeid又必須反回一個類型為type_info類型的對象的引用,所以怎樣在typeid函數中創建一個type_info類的對象以便讓函數反回type_info類對象的引用就成了問題。這可能是把typid函數聲明為了type_info類的友元函數來實現的,默認構造函數是私有的并不能阻止該類的友元函數創建該類的對象。所以typeid函數如果是友元的話就可以訪問type_info類的私有成員,從而可以創建type_info類的對象,從而可以創建反回類型為type_info類的引用。舉個例子class A{private:A(){} A(const A&){} A& operator =(const A&){} friend A& f();};這里把類A的默認構造函數,復制構造函數和賦值操作符定為私有從而防止創建類A的對象,但函數f()是類A的友元,所以在函數f()中可以創建類A的對象。同時為了實現函數f()反回的對象類型是A的引用,就必須在函數f中創建一個類A的對象以作為函數f的反回值,比如函數f可以這樣定義A& f(){A ma; cout<<”f”<<endl; return ma}。   4、因為typeid函數是type_info類的對象,也就是說可以用該函數訪問type_info類的成員,即type_info類中重載的= =和!=運算符,name()和before()成員函數,比如typid(a).naem()和typid(a)= =typid(b)等等。   5、typeid函數的使用原理:該函數的形式為type_info& typeid(object)其中object是任何類型的對象,可以是內置類型和用戶創建的類類型。可以看出typeid即是一個函數,同時他也是type_info類的對象,即typeid可以訪問類type_info類的成員,也可以做為一個單獨的函數來使用。做個簡單的例子,比如   class A{private: A(){b=3;cout<<”A”<<endl;} //私有的默認構造函數   public: void name(){cout<<”NA”<<endl;} int b;   friend A f();}; //函數f()是類A的友元,因此在f中可以創建類A的對象。   A f() //函數f()在這里即是類A的一個對象,也是一個單獨的函數。   { A m; //創建類A的對象,因為函數f是類A的友元,因此可以創建類A的對象   cout<<”F”<<endl; return m;}   main()   { f().name(); //函數f()作為類A的對象使用,這里要注意程序的執行順序,首先執行函數f()中的語句A m,因此調用類A的默認構造函數輸出A,然后執行A m;后面的語句,輸出F,再然后調用類A中的成員函數name輸出NA.   f(); } //函數f()單獨作為函數使用。   我們創建一個類A,其中A的默認構造函數是私有的,也就是說不能用默認構造函數創建類A的對象。函數f()是類A的友元,且反回一個類A的對象,因為f()函數是類A的友元,所以在函數f中可以用默認構造函數創建類A的對象,這時函數f()同時是一個函數,也是類A的對象,因此也可以訪問類A中的成員。   6、typeid函數使用方式一:使用type_info類中的name()成員函數反回對象的類型的名稱。其方法為:typeid(object).name()其中object是要顯示的對象的類型名,該函數反回的名字因編譯器而定。這里要注意的就是使用方式一中提到的虛函數類型的問題,即如果有類A,且有虛函數,類B,C,D都是從類A派生的,且都重定義了類A中的虛函數,這時有類A的指針p,再把對象類B的對象的地址賦給指針p,則typeid(p).name()將反回的類型將是A*,因為這里的p表示的是一個指針,該指針是類型為A的指針,所以反回A*,而typeid(*p).name()將反回B,因為指針p是指向類B的對象的,而*p就表示的是類B的對象的類型,所以反回B。   7、typeid函數使用方式二:使用type_info類中重載的= =與!=比較兩個對象的類型是否相等。使用該方法需要調用類type_info中重載的= =和!=操作符,其使用方法為typid(object1)= =typid(object2);如果兩個對象的類型相等則反回1,如果不相等則為0。這種使用方法通常用于比較兩個帶有虛函數的類的對象是否相等,比如有類A,其中定義有虛函數,而類B,類C,類D,都是從類A派生而來的且重定義了該虛函數,這時有個類A的指針p和p1,按照虛函數的原理,基類的指針可以指向任何派生類的對象,在這時就有可能需要比較兩個指針是否指向同一個對象,這時就可以這樣使用typeid了,typeid(*p)= =typeid(*p1);這里要注意的是typeid(*p)與typeid(p)是指的不同的對象類型,typeid(p)表示的是p的類型,在這里p是一個指針,這個指針指向的是類A的對象,所以p的類型是A*,而typeid(*p)則不一樣,*p表示的是指針p實際所指的對象的類型,比如這里的指針p指向派生類B,則typeid(*p)的類型為B。所以在測試兩個指針的類型是否是相等時應使用*p,即typeid(*p)= =typeid(*p1)。如果是typeid(p)= =typeid(p1)的話,則無論指針p和p1指向的什么派生類對象,他們都是相等的,因為都是A *的類型。   8、強制類型轉換運算符:C++有四種強制類型轉換符,分別是dynamic_cast,const_cast,static_cast,reinterpret_cast。其中dynamic_cast與運行時類型轉換密切相關,在這里我們先介紹dynamic_cast,其他三種在后面介紹。   8.1、dynamic_cast強制轉換運算符:該轉換符用于將一個指向派生類的基類指針或引用轉換為派生類的指針或引用,注意dynamic_cast轉換符只能用于含有虛函數的類,其表達式為dynamic_cast<類型>(表達式),其中的類型是指把表達式要轉換成的目標類型,比如含有虛函數的基類B和從基類B派生出的派生類D,則B *pb; D *pd, md; pb=&md; pd=dynamic<D*>(pb); 最后一條語句表示把指向派生類D的基類指針pb轉換為派生類D的指針,然后將這個指針賦給派生類D的指針pd,有人可能會覺得這樣做沒有意義,既然指針pd要指向派生類為什么不pd=&md;這樣做更直接呢?有些時候我們需要強制轉換,比如如果指向派生類的基類指針B想訪問派生類D中的除虛函數之外的成員時就需要把該指針轉換為指向派生類D的指針,以達到訪問派生類D中特有的成員的目的,比如派生類D中含有特有的成員函數g(),這時可以這樣來訪問該成員dynamic_cast<D*>(pb)->g();因為dynamic_cast轉換后的結果是一個指向派生類的指針,所以可以這樣訪問派生類中特有的成員。但是該語句不影響原來的指針的類型,即基類指針pb仍然是指向基類B的。如果單獨使用該指針仍然不能訪問派生類中特有的成員。一般情況下不推見這樣使用dynamic_cast轉換符,因為dynamic_cast的轉換并不會總是成功的,具體情況在后面介紹。   8.2、dynamic_cast的注意事項:dynamic_cast轉換符只能用于指針或者引用。dynamic_cast轉換符只能用于含有虛函數的類。dynamic_cast轉換操作符在執行類型轉換時首先將檢查能否成功轉換,如果能成功轉換則轉換之,如果轉換失敗,如果是指針則反回一個0值,如果是轉換的是引用,則拋出一個bad_cast異常,所以在使用dynamic_cast轉換之間應使用if語句對其轉換成功與否進行測試,比如pd=dynamic_cast<D*>(pb); if(pd){…}else{…},或者這樣測試if(dynamic_cast<D*>(pb)){…}else{…}。   8.3、const_cast操作符:其表達式為const_cast<類型>(表達式),其中類型指要把表達式轉換為的目標類型。該操作符用于改變const和volatile,const_cast最常用的用途就是刪除const屬性,如果某個變量在大多數時候是常量,而在某個時候又是需要修改的,這時就可以使用const_cast操作符了。const_cast操作符不能改變類型的其他方面,他只能改變const或volatile,即const_cast不能把int改變為double,但可以把const int改變為int。const_cast只能用于指針或引用。const_cast的用法舉例比如:int a=3; const int *b=&a; int* c; c=const_cast<int*>(b); *c=4; cout<<a<<*c;這時輸出兩個4,如果不使用const_cast轉換符則常量指針*c的值是不能改變的,在這里使用const_cast操作符,通過指針b就能改變常量指針和變量a的值。   8.4、static_cast操作符:該操作符用于非多態類型的轉換,任何標準轉換都可以使用他,即static_cast可以把int轉換為double,但不能把兩個不相關的類對象進行轉換,比如類A不能轉換為一個不相關的類B類型。static_cast本質上是傳統c語言強制轉換的替代品。   8.5、reinterpret_cast操作符:該操作符用于將一種類型轉換為另一種不同的類型,比如可以把一個整型轉換為一個指針,或把一個指針轉換為一個整型,因此使用該操作符的危險性較高,一般不應使用該操作符。   9、使用 typeid 要注意一個問題,那就是某些編譯器(如 Visual C++)默認狀態是禁用 RTTI 的,目的是消除性能上的開銷。如果你的程序確實使用了 RTTI,一定要記住在編譯前啟用 RTTI。使用 typeid 可能產生一些將來的維護問題。假設你決定擴展上述的類層次,從MediaFile 派生另一個叫 LocalizeMedia 的類,用這個類表示帶有不同語言說明文字的媒體文件。但 LocalizeMedia 本質上還是個 MediaFile 類型的文件。因此,當用戶在該類文件圖標上單擊右鍵時,文件管理器必須提供一個“播放”菜單。可惜 build()成員函數會調用失敗,原因是你沒有檢查這種特定的文件類型。為了解決這個問題,你必須象下面這樣對 build() 打補丁:   void menu::build(const File * pfile)   {   //......   else if (typeid(*pfile)==typeid(LocalizedMedia))   {   add_option("play");   }   }   唉,這種做法真是顯得太業余了,以后每次添加新的類,毫無疑問都必須打類似的補丁。顯然,這不是一個理想的解決方案。這個時候我們就要用到 dynamic_cast,這個運算符用于多態編程中保證在運行時發生正確的轉換(即編譯器無法驗證是否發生正確的轉換)。用它來確定某個對象是 MediaFile 對象還是它的派生類對象。dynamic_cast 常用于從多態編程基類指針向派生類指針的向下類型轉換。它有兩個參數:一個是類型名;另一個是多態對象的指針或引用。其功能是在運行時將對象強制轉換為目標類型并返回布爾型結果R簿褪撬擔綣煤曬Φ夭⑶沂嵌慕?*pfile 強制轉換為 MediaFile,那么 pfile的動態類型是 MediaFile 或者是它的派生類。否則,pfile 則為其它的類型:   void menu::build(const File * pfile)   {   if (dynamic_cast <MediaFile *> (pfile))   {   // pfile 是 MediaFile 或者是MediaFile的派生類 LocalizedMedia   add_option("play");   }   else if (dynamic_cast <TextFile*> (pfile))   {   // pfile 是 TextFile 是TextFile的派生類   add_option("edit");   }   }   細細想一下,雖然使用 dynamic_cast 確實很好地解決了我們的問題,但也需要我們付出代價,那就是與 typeid 相比,dynamic_cast 不是一個常量時間的操作。為了確定是否能完成強制類型轉換,dynamic_cast`必須在運行時進行一些轉換細節操作。因此在使用 dynamic_cast 操作時,應該權衡對性能的影響。

            posted @ 2010-06-07 17:02 莫失莫忘 閱讀(158) | 評論 (0)編輯 收藏

                     我們現在普遍用的是DX9了,但是DX8就已經沒有DirectDraw了,已經被整合進入DirectX Graphics了。
                     我現在在看《windows游戲編程大師技巧》,里面是從DirectDraw開始講解的,現在基本都是D3D了,所以我
            要不要直接看D3D呢?DirectDraw只是作為基本了解。
                    了解到DX9下除了用DirectDraw7外,就只能用D3D接口模擬呢!還有個D3DXSprite的頭文件可以用。
                    我的D3D基本入門而已,書上說DirectDraw是D3D的基礎,我怕錯過了一些關鍵的只是,所以到過頭來看DirectDraw
            了。
                    大家對我的學習過程有沒有更好的建議?!指教下
                     那本《openGL超級寶典(第四版)》是不是等我D3D比較可以了的時候的必看書籍,我需要對計算機的圖像原理
            更加了解。
                    有沒有人知道DirectDraw現在還有哪些方面的應用?
                    (順便抱怨下,CPPBLOG的這個寫日志的系統好慢)

            posted @ 2009-10-20 18:13 莫失莫忘 閱讀(139) | 評論 (0)編輯 收藏

            僅列出標題
            共2頁: 1 2 

            posts - 15, comments - 0, trackbacks - 0, articles - 0

            Copyright © 莫失莫忘

            欧美丰满熟妇BBB久久久| 2021精品国产综合久久| 伊人久久无码精品中文字幕| 97精品依人久久久大香线蕉97| 99久久超碰中文字幕伊人| 亚洲精品WWW久久久久久| 婷婷国产天堂久久综合五月| 99久久精品免费看国产| 国产欧美久久一区二区| 久久久久亚洲av无码专区导航| 久久久久亚洲精品无码网址| 久久青青草原综合伊人| 久久er热视频在这里精品| 久久精品成人| 亚洲国产天堂久久综合| 国产精品久久波多野结衣| 综合久久一区二区三区 | 欧美亚洲国产精品久久高清| 狠狠久久综合伊人不卡| 国产福利电影一区二区三区久久久久成人精品综合 | 亚洲国产精品无码久久一线| 狠狠色丁香婷婷久久综合五月 | 久久天天躁夜夜躁狠狠| 伊人久久久AV老熟妇色| 精品无码久久久久久久久久| 日韩人妻无码精品久久久不卡| 久久亚洲国产精品123区| 青青青伊人色综合久久| 久久99精品国产麻豆宅宅| 久久狠狠高潮亚洲精品| 久久午夜羞羞影院免费观看| 久久91精品国产91| 久久综合视频网站| 久久亚洲国产精品123区| 久久强奷乱码老熟女网站| 久久国产视频网| 久久一区二区三区免费| 四虎影视久久久免费| 久久er99热精品一区二区| 狼狼综合久久久久综合网| 久久精品国产亚洲AV无码娇色|