青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

積木

No sub title

  C++博客 :: 首頁 :: 聯系 :: 聚合  :: 管理
  140 Posts :: 1 Stories :: 11 Comments :: 0 Trackbacks

常用鏈接

留言簿(1)

我參與的團隊

搜索

  •  

最新評論

閱讀排行榜

評論排行榜

#

原文出自:http://www.wuzesheng.com/?p=840

C++中內存的動態分配與管理永遠是一個讓C++開發者頭痛的問題,本文通過對C++中內存的動態分配釋放的基本原理的介紹,讓讀者朋友能對C++中的內存的動態分配與釋放有較為深入的理解,從而更好駕馭C++程序。

1. 函數(Function)
(1) operator new function

1
2
void * ::operator new(size_t);	                //Global
void * class-name::operator new(size_t); 	//Class


上面是C++中operator new function的原型,一個是全局類型的,一個的類成員類型的。全局類型的operator new函數在下面兩種情況下被調用:一種是在分配C++內建(built-in)類型的動態內存時,一種是在分配用戶沒有自己定義operator new成員函數的用戶自定義類型的動態內存時。 如果用戶在自己定義的類型中,定義了operator new函數,那么用戶在用new申請該類型的動態內存時, 便會調用該類型的成員函數operator new, 而不是全局的operator new。

另外,我們注意到,上面的原型中函數的返回值為void *類型, 第一個參數為size_t類型,這個是C++編譯器要求的,如果要自己重載operator new函數,返回值必須為void* 類型,第一個參數必須為size_t類型,否則,編譯器會返回如下錯誤信息:

1
error: ‘operator new’ takes type ‘size_t’ (‘unsigned int’) as first parameter

這里需要注意的一點是,我們可以利用operator new function可以重載的特點,可以通過參數傳入一些額外的信息,來調試程序,檢測內存泄露等。比如,我們可以像下面這樣重載,傳入調用處的行號,函數名,這樣就可以跟蹤內存的分配使用情況:

1
2
3
4
5
void * operator new(size_t unSize, int nLine, const char * pFunc)
{
    prinft("Line: %d, Func: %s, allocate %u byte(s)\n", nLine, pFunc, unSize);
    return malloc(unSize);
}

(2) operator delete function

1
2
void operator delete( void * );
void operator delete( void *, size_t );

上面是operator delete function的原型。operator delete function也有全局的和類成員的兩種。這里需要注意,一個類只能有一個operator delete function做為其成員函數,而且必須為上面兩種中的其中一種,沒有其它的形式。如果一個類實現了自己的operator delete function成員函數,那么在釋放該類型的內存時,編譯器便會調用成員operator delete function, 而不是全局的。

上面的兩種原型,第一種,在調用的時候,編譯器會把要釋放的內存的首地址傳入,第二種,在調用的時候,編譯器會把要釋放的內存的首地址和大小都傳入。因此,可以利用這一特性,如果我們在基類中實現第二種形式的operator delete function的成員函數,那么便可以用之來釋放子類類型的內存(具體參考最后面的例子)。

2. 運算符(Operator)
(1) new operator

1
2
[::] new [placement] new-type-name [new-initializer]
[::] new [placement] ( type-name ) [new-initializer]

注:上面的’[]‘表示在其中的部分是optional(可選的)
上面是new operator的原型。在C++中,動態內存的分配,通常都是調用new operator來完成的,利用new operator來分配動態內存,編譯器要做下面兩項工作:

  • a. 調用operator new function分配內存(allocate the memory)
  • b. 調用構造函數(call the constructor)來進行初始化

下面來說一說new operator的原型中各部分到底是干什么的:
placement: 如果你重載了operator new function, placement可以用來傳遞額外的參數
type-name: 指定要分配的內存的類型,可以是內建(built-in)類型,也可以是用戶自定義類型
new-initializer: 指定對分配后內存的初始化的參數,也就的構造函數的參數 。這里需要注意一點,在分配一個對象的數組類型的內存時,不能夠指定初始化參數;換言之,要想分配一個對象的數組類型的內存,該對象必須有缺省構造函數

(2) delete opeartor

1
2
[::] delete cast-expression
[::] delete [ ] cast-expression

上面是delete operator的原型,第一種用來釋放普通的對象(包括內建類型)類型的內存,第二種用來釋放對象的數組類型的內存。在C++中,用new operator分配的動態內存,必須調用delete operator來釋放,通常用delete operator釋放內存編譯器要做下面兩項工作:

  • a. 調用對象析構函數來析構對象
  • b. 調用operator delete function來釋放內存(deallocate the memory)


3. 關于new/delete使用過程中一些需要注意的點
(1)如何區別operator new/delete function 與 new/delete operator ?
通過上面的講述,不難看出,我們分配/釋放動態內存,調用的是new/delete operator, 而在調用new/delete的過程中,編譯器會自動調用operator new/delete function來完成實際的內存分配/釋放的工作

(2) 用delete operator去釋放一塊不是由new operator釋放的內存,結果是不可預料的,因此,切記,operator new與operator delete一定要配對使用,這是寫好程序的基礎

(3) new operator調用失敗會拋出std::bad_alloc異常,前提是你沒有自己重載對應的operator new function;delete operator失敗,常見的原因是多次delete同一塊內存

(4) 如果一塊內存被delete后,再對它解引用(Dereference),結果也是不可預測的,很可能導致程序崩潰

(5) delete一個空(NULL)指針是安全的,沒有任何害處的

(6) 類成員類型的operator new/delete函數必須為靜態(static)函數,因此它們不能為虛函數(virtual function),也遵守public, protected, private的訪問權限控制

4. 關于上面所講的內容的一些例子:
程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include <stdio .h>
#include <stdlib .h>
 
void * operator new(size_t unSize)
{
    printf("operator new called\n");
    return malloc(unSize);
}
 
void * operator new(size_t unSize, int nLine, const char * pFunc)
{
    printf("operator new called, line: %d, func: %s\n",
            nLine, pFunc);
    return malloc(unSize);
}
 
void operator delete(void * pMem)
{
    printf("delete1\n");
    free(pMem);
}
 
class A
{
public:
 
    A(int a = 0) :
        _a(a)
    {   
        printf("constructor called\n");
    }   
    {
        printf("~A()\n");
    }
 
    static void operator delete(void * pMem, size_t unSize)
    {
        printf("delete2: %u\n", unSize);
        free(pMem);
    }
 
private:
 
    int _a;
};
 
class B: public A
{
public:
 
    ~B()
    {
        printf("~B()\n");
    }
 
    int _b;
 
    int _bb;
};
 
int main()
{
    A * pA = new A(10);
    printf("#######\n");
 
    A * pB = new (__LINE__, __func__) B();
    printf("#######\n");
 
    A * szA = new A[10];
    printf("#######\n");
 
    delete pA; 
    printf("#######\n");
 
    delete pB; 
    printf("#######\n");
 
    delete [] szA;
    printf("#######\n");
 
    char * pC = NULL;
    delete pC; 
}
</stdlib></stdio>

運行結果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
wuzesheng@wuzesheng-ubuntu:~/Program$ ./a.out 
operator new called
constructor called
#######
operator new called, line: 68, func: main
constructor called
#######
operator new called
constructor called
constructor called
constructor called
constructor called
constructor called
constructor called
constructor called
constructor called
constructor called
constructor called
#######
~A()
delete2: 8
#######
~B()
~A()
delete2: 16
#######
~A()
~A()
~A()
~A()
~A()
~A()
~A()
~A()
~A()
~A()
delete1
#######
delete1

上面的程序很簡單,我在這里不做過多的解釋,感興趣的朋友可以自己分析一下。

通過我上面的講解,相信大多數朋友應該對C++中內存的動態分配與釋放有了較為深入的理解。后續我還有可能寫一些關于C++中內存管理的文章,只有把本文所講的內容與后續的內存管理的一些常見的方法結合起來,我們才寫出更加健壯的C++程序。歡迎讀者朋友留言一起交流!

posted @ 2012-07-16 12:37 Jacc.Kim 閱讀(305) | 評論 (0)編輯 收藏

原文出自:http://visionsky.blog.51cto.com/733317/151760

聯合(union)在C/C++里面見得并不多,但是在一些對內存要求特別嚴格的地方,聯合又是頻繁出現,那么究竟什么是聯合、怎么去用、有什么需要注意的地方呢?就這些問題,我試著做一些簡單的回答,里面肯定還有不當的地方,歡迎指出!
1、什么是聯合?
   “聯合”是一種特殊的類,也是一種構造類型的數據結構。在一個“聯合”內可以定義多種不同的數據類型, 一個被說明為該“聯合”類型的變量中,允許裝入該“聯合”所定義的任何一種數據,這些數據共享同一段內存,已達到節省空間的目的(還有一個節省空間的類型:位域)。 這是一個非常特殊的地方,也是聯合的特征。另外,同struct一樣,聯合默認訪問權限也是公有的,并且,也具有成員函數。
2、聯合與結構的區別?
   “聯合”與“結構”有一些相似之處。但兩者有本質上的不同。在結構中各成員有各自的內存空間, 一個結構變量的總長度是各成員長度之和(空結構除外,同時不考慮邊界調整)。而在“聯合”中,各成員共享一段內存空間, 一個聯合變量的長度等于各成員中最長的長度。應該說明的是, 這里所謂的共享不是指把多個成員同時裝入一個聯合變量內, 而是指該聯合變量可被賦予任一成員值,但每次只能賦一種值, 賦入新值則沖去舊值。
   下面舉一個例了來加對深聯合的理解。
    例4:
#include <stdio.h>
void main()
{
        union number
        {                   /*定義一個聯合*/
                int i;
                struct
                {             /*在聯合中定義一個結構*/
                        char first;
                        char second;
                }half;
        }num;
        num.i=0x4241;         /*聯合成員賦值*/
        printf("%c%c\n", num.half.first, num.half.second);
        num.half.first='a';   /*聯合中結構成員賦值*/
        num.half.second='b';
        printf("%x\n", num.i);
        getchar();
}
    輸出結果為:
     AB
     6261
    從上例結果可以看出: 當給i賦值后, 其低八位也就是first和second的值; 當給first和second賦字符后, 這兩個字符的ASCII碼也將作為i 的低八位和高八位。
3、如何定義?
   例如:
    union test
    {
      test() { }
      int office;
      char teacher[5];
    };
    定義了一個名為test的聯合類型,它含有兩個成員,一個為整型,成員名office;另一個為字符數組,數組名為teacher。聯合定義之后,即可進行聯合變量說明,被說明為test類型的變量,可以存放整型量office或存放字符數組teacher。
4、如何說明?
   聯合變量的說明有三種形式:先定義再說明、定義同時說明和直接說明。
   以test類型為例,說明如下:
    1) union test
       {
         int office;
         char teacher[5];
       };
       union test a,b;    /*說明a,b為test類型*/
    2) union test
       {
         int office;
         char teacher[5];
       } a,b;
    3) union
       {
         int office;
         char teacher[5];
       } a,b;
       經說明后的a,b變量均為test類型。a,b變量的長度應等于test的成員中最長的長度,即等于teacher數組的長度,共5個字節。a,b變量如賦予整型值時,只使用了4個字節,而賦予字符數組時,可用5個字節。
5、如何使用?
   對聯合變量的賦值,使用都只能是對變量的成員進行。聯合變量的成員表示為:     
聯合變量名.成員名 
例如,a被說明為test類型的變量之后,可使用a.class、a.office 
不允許只用聯合變量名作賦值或其它操作,也不允許對聯合變量作初始化賦值,賦值只能在程序中進行。
還要再強調說明的是,一個聯合變量,每次只能賦予一個成員值。換句話說,一個聯合變量的值就是聯合變員的某一個成員值。
6、匿名聯合
   匿名聯合僅僅通知編譯器它的成員變量共同享一個地址,而變量本身是直接引用的,不使用通常的點號運算符語法.例如:
     #i nclude <iostream>
     void main()
     {
         union{
                int test;
                char c;
               };         
        test=5;
        c=′a′;
        std::cout<<i<<" "<<c;
     }
    正如所見到的,聯合成分象聲明的普通局部變量那樣被引用,事實上對于程序而言,這也正是使用這些變量的方式.另外,盡管被定義在一個聯合聲明中,他們與同一個程序快那的任何其他局部變量具有相同的作用域級別.這意味這匿名聯合內的成員的名稱不能與同一個作用域內的其他一直標志符沖突.
    對匿名聯合還存在如下限制:
    因為匿名聯合不使用點運算符,所以包含在匿名聯合內的元素必須是數據,不允許有成員函數,也不能包含私有或受保護的成員。還有,全局匿名聯合必須是靜態(static)的,否則就必須放在匿名名字空間中。
7、幾點需要討論的地方:
   1、聯合里面那些東西不能存放?
      我們知道,聯合里面的東西共享內存,所以靜態、引用都不能用,因為他們不可能共享內存。
   2、類可以放入聯合嗎?
      我們先看一個例子:
      class Test
      {
      public:
    Test():data(0) { }
      private:
          int data;
      };
     typedef union _test
     {
Test test;  
     }UI;  
     編譯通不過,為什么呢?
     因為聯合里不允許存放帶有構造函數、析夠函數、復制拷貝操作符等的類,因為他們共享內存,編譯器無法保證這些對象不被破壞,也無法保證離開時調用析夠函數。
    3、又是匿名惹的禍??
       我們先看下一段代碼:
class test
{
        public:
             test(const char* p);
             test(int in);
             const operator char*() const {return
data.ch;}
             operator long() const {return data.l;}
        private:
     enum type {Int, String };
            union
     {
const char* ch;
int i;
      }datatype;
      type stype;
      test(test&);
      test& operator=(const test&);
        };
       test::test(const char *p):stype
(String),datatype.ch(p)     { }
       test::test(int in):stype(Int),datatype.l(i)     {
}
     看出什么問題了嗎?呵呵,編譯通不過。為什么呢?難道datatype.ch(p)和datatype.l(i)有問題嗎?
     哈哈,問題在哪呢?讓我們來看看構造test對象時發生了什么,當創建test對象時,自然要調用其相應的構造函數,在構造函數中當然要調用其成員的構造函數,所以其要去調用datatype成員的構造函數,但是他沒有構造函數可調用,所以出
錯。
     注意了,這里可并不是匿名聯合!因為它后面緊跟了個data!
    4、如何有效的防止訪問出錯?
       使用聯合可以節省內存空間,但是也有一定的風險:通過一個不適當的數據成員獲取當前對象的值!例如上面的ch、i交錯訪問。
       為了防止這樣的錯誤,我們必須定義一個額外的對象,來跟蹤當前被存儲在聯合中的值得類型,我們稱這個額外的對象為:union的判別式。
       一個比較好的經驗是,在處理作為類成員的union對象時,為所有union數據類型提供一組訪問函數。
posted @ 2012-06-27 10:35 Jacc.Kim 閱讀(234) | 評論 (0)編輯 收藏

原文出自:http://www.cnblogs.com/JCSU/articles/1051826.html

程序員們經常編寫內存管理程序,往往提心吊膽。如果不想觸雷,唯一的解決辦法就是發現所有潛伏的地雷并且排除它們,躲是躲不了的。本文的內容比一般教科書的要深入得多,讀者需細心閱讀,做到真正地通曉內存管理。

     內存分配方式 

   (1)從靜態存儲區域分配。內存在程序編譯的時候就已經分配好,這塊內存在程序的整個運行期間都存在。例如全局變量,static變量。
   (2)在棧上創建。在執行函數時,函數內局部變量的存儲單元都可以在棧上創建,函數執行結束時這些存儲單元自動被釋放。棧內存分配運算內置于處理器的指令集中,效率很高,但是分配的內存容量有限。
   (3) 從堆上分配,亦稱動態內存分配。程序在運行的時候用malloc或new申請任意多少的內存,程序員自己負責在何時用free或delete釋放內存。動態內存的生存期由我們決定,使用非常靈活,但問題也最多。
 
     常見的內存錯誤及其對策 

     發生內存錯誤是件非常麻煩的事情。編譯器不能自動發現這些錯誤,通常是在程序運行時才能捕捉到。而這些錯誤大多沒有明顯的癥狀,時隱時現,增加了改錯的難度。有時用戶怒氣沖沖地把你找來,程序卻沒有發生任何問題,你一走,錯誤又發作了。 常見的內存錯誤及其對策如下: 

     * 內存分配未成功,卻使用了它

編程新手常犯這種錯誤,因為他們沒有意識到內存分配會不成功。常用解決辦法是,在使用內存之前檢查指針是否為NULL。如果指針p是函數的參數,那么在函數的入口處用assert(p!=NULL)進行檢查。如果是用malloc或new來申請內存,應該用if(p==NULL) 或if(p!=NULL)進行防錯處理。

* 內存分配雖然成功,但是尚未初始化就引用它

犯這種錯誤主要有兩個起因:一是沒有初始化的觀念;二是誤以為內存的缺省初值全為零,導致引用初值錯誤(例如數組)。內存的缺省初值究竟是什么并沒有統一的標準,盡管有些時候為零值,我們寧可信其無不可信其有。所以無論用何種方式創建數組,都別忘了賦初值,即便是賦零值也不可省略,不要嫌麻煩。

* 內存分配成功并且已經初始化,但操作越過了內存的邊界

例如在使用數組時經常發生下標“多1”或者“少1”的操作。特別是在for循環語句中,循環次數很容易搞錯,導致數組操作越界。

* 忘記了釋放內存,造成內存泄露

含有這種錯誤的函數每被調用一次就丟失一塊內存。剛開始時系統的內存充足,你看不到錯誤。終有一次程序突然死掉,系統出現提示:內存耗盡。

動態內存的申請與釋放必須配對,程序中malloc與free的使用次數一定要相同,否則肯定有錯誤(new/delete同理)。

* 釋放了內存卻繼續使用它

有三種情況:

(1)程序中的對象調用關系過于復雜,實在難以搞清楚某個對象究竟是否已經釋放了內存,此時應該重新設計數據結構,從根本上解決對象管理的混亂局面。

(2)函數的return語句寫錯了,注意不要返回指向“棧內存”的“指針”或者“引用”,因為該內存在函數體結束時被自動銷毀。

(3)使用free或delete釋放了內存后,沒有將指針設置為NULL。導致產生“野指針”。

【規則1】用malloc或new申請內存之后,應該立即檢查指針值是否為NULL。防止使用指針值為NULL的內存。

【規則2】不要忘記為數組和動態內存賦初值。防止將未被初始化的內存作為右值使用。

【規則3】避免數組或指針的下標越界,特別要當心發生“多1”或者“少1”操作。

【規則4】動態內存的申請與釋放必須配對,防止內存泄漏。

【規則5】用free或delete釋放了內存之后,立即將指針設置為NULL,防止產生“野指針”。

指針與數組的對比

C++/C程序中,指針和數組在不少地方可以相互替換著用,讓人產生一種錯覺,以為兩者是等價的。

數組要么在靜態存儲區被創建(如全局數組),要么在棧上被創建。數組名對應著(而不是指向)一塊內存,其地址與容量在生命期內保持不變,只有數組的內容可以改變。

指針可以隨時指向任意類型的內存塊,它的特征是“可變”,所以我們常用指針來操作動態內存。指針遠比數組靈活,但也更危險。

下面以字符串為例比較指針與數組的特性

1 修改內容

下例中,字符數組a的容量是6個字符,其內容為hello。a的內容可以改變,如a[0]= 'x'。指針p指向常量字符串"world"(位于靜態存儲區,內容為world),常量字符串的內容是不可以被修改的。從語法上看,編譯器并不覺得語句 p[0]= 'x'有什么不妥,但是該語句企圖修改常量字符串的內容而導致運行錯誤。

#include<iostream.h>

void main()
{
    
char a[] = "hello";
    a[
0= 'x';
    cout 
<< a << endl;
    
char *= "world"// 注意p指向常量字符串
    p[0= 'x'// 編譯器不能發現該錯誤
    cout << p << endl;
}

2 內容復制與比較

不能對數組名進行直接復制與比較。下例中,若想把數組a的內容復制給數組b,不能用語句 b = a ,否則將產生編譯錯誤。應該用標準庫函數strcpy進行復制。同理,比較b和a的內容是否相同,不能用if(b==a) 來判斷,應該用標準庫函數strcmp進行比較。

語句p = a 并不能把a的內容復制指針p,而是把a的地址賦給了p。要想復制a的內容,可以先用庫函數malloc為p申請一塊容量為strlen(a)+1個字符的內存,再用strcpy進行字符串復制。同理,語句if(p==a) 比較的不是內容而是地址,應該用庫函數strcmp來比較。

// 數組…
char a[] = "hello";
char b[10];
strcpy(b, a); 
// 不能用 b = a;
if(strcmp(b, a) == 0// 不能用 if (b == a)

// 指針…
int len = strlen(a);
char *= (char *)malloc(sizeof(char)*(len+1));
strcpy(p,a); 
// 不要用 p = a;
if(strcmp(p, a) == 0// 不要用 if (p == a)

 3 計算內存容量

用運算符sizeof可以計算出數組的容量(字節數)。下例(a)中,sizeof(a)的值是12(注意別忘了' ')。指針p指向a,但是 sizeof(p)的值卻是4。這是因為sizeof(p)得到的是一個指針變量的字節數,相當于sizeof(char*),而不是p所指的內存容量。 C++/C語言沒有辦法知道指針所指的內存容量,除非在申請內存時記住它。注意當數組作為函數的參數進行傳遞時,該數組自動退化為同類型的指針。下例(b)中,不論數組a的容量是多少,sizeof(a)始終等于sizeof(char *)。

示例(a)
char a[] = "hello world";
char *= a;
cout
<< sizeof(a) << endl; // 12字節
cout<< sizeof(p) << endl; // 4字節

示例(b)
void Func(char a[100])
{
 cout
<< sizeof(a) << endl; // 4字節而不是100字節
}


 

posted @ 2012-06-25 10:25 Jacc.Kim 閱讀(283) | 評論 (0)編輯 收藏

3D游戲開發中,該變換時常發生。下面記錄下,以備隨時查詢用。

說明:
1)
已經向量v就不用說,可以是3維空間中的任意向量。(不論位置在哪都沒關系,因為向量是與位置無關的)
2)
繞已知向量n旋轉。此處的n向量,最好要規范化成單位向量。為什么需要此要求呢?其實很簡單,如果不規范化成單位向量,那么變換后的結果向量(假如稱為v'),其模就不會等于原向量v的模。因此就會出錯。(當然,如果非要用非規范化的單位向量參與計算的話,我們也是可以通過將v'進行一些處理,而得到最終想要的向量。)

下面,確認一下,變換矩陣以及變化公式所需的參數信息:
v(vx     ,      vy     ,  vz)                                :
為已經向量
n(nx    ,    ny     ,  nz)                                :
v向量繞n旋轉的基向量
R(n     ,    angle)                                         : 為旋轉所需的變換矩陣。(注釋:angle就是角度,本來可以直接用那些希臘字母,結果發現用了,在此,我就輸入不了中文與英文字符了。蛋疼)

v'(vx'   ,    vy'     , vz')                                : 為變換后最終要得到的結果向量

根據3D變換基礎知識,可得如下公式:
v' = vR(n, angle)
其中,v向量已知。R(n, angle)根據推導,可得如下式子:
                     [ p' ]    [ nx2(1 - cos(angle)) + cos(angle)                            nxny(1 - cos(angle)) + nzsin(angle)                       nxnz(1 - cos(angle)) - nysin(angle) ]
R(n, angle) =  | q' | = | nxny(1 - cos(angle)) - nzsin(angle)                        ny2(1 - cos(angle)) + cos(angle)                           nynz(1 - cos(angle)) + nxsin(angle) |
                     [ r' ]     [ nxnz(1 - cos(angle)) + nysin(angle)                       nynz(1 - cos(angle)) - nxsin(angle)                        nz2(1 - cos(angle)) + cos(angle)    ]

所以,可得最終的v'向量。具體如下:

v' = vR = (vx, vy, vz)R;

vx'   = vx * (nx2(1 - cos(angle)) + cos(angle));
vx' += vy * (nxny(1 - cos(angle)) - nzsin(angle));
vx' += vz * (nxnz(1 - cos(angle)) + nysin(angle));

vy'   = vx * (nxny(1 - cos(angle)) + nzsin(angle));
vy' += vy * (ny2(1 - cos(angle)) + cos(angle));
vy' += vz * (nynz(1 - cos(angle)) - nxsin(angle));

vz'   = vx * (nxnz(1 - cos(angle)) - nysin(angle));
vz' += vy * (nynz(1 - cos(angle)) + nxsin(angle));
vz' += vz * (nz2(1 - cos(angle)) + cos(angle));

-----------------------------------------------------------------
有了上面的知識,現在就可以很容易理解。如下一段旋轉攝像機方向的代碼了:(注:代碼出自徐明亮作者所著《opengl游戲編程》一書中的內容)

/**  旋轉攝像機方向  */
void Camera::rotateView(float angle, float x, float y, float z)
{
    Vector3 newView;

    
/** 計算方向向量 */
    Vector3 view 
= m_View - m_Position;        

    
/** 計算 sin 和cos值 */
    
float cosTheta = (float)cos(angle);
    
float sinTheta = (float)sin(angle);

    
/** 計算旋轉向量的x值 */
    newView.x  
= (cosTheta + (1 - cosTheta) * x * x)        * view.x;
    newView.x 
+= ((1 - cosTheta) * x * y - z * sinTheta)    * view.y;
    newView.x 
+= ((1 - cosTheta) * x * z + y * sinTheta)    * view.z;

    
/** 計算旋轉向量的y值 */
    newView.y  
= ((1 - cosTheta) * x * y + z * sinTheta)    * view.x;
    newView.y 
+= (cosTheta + (1 - cosTheta) * y * y)        * view.y;
    newView.y 
+= ((1 - cosTheta) * y * z - x * sinTheta)    * view.z;

    
/** 計算旋轉向量的z值 */
    newView.z  
= ((1 - cosTheta) * x * z - y * sinTheta)    * view.x;
    newView.z 
+= ((1 - cosTheta) * y * z + x * sinTheta)    * view.y;
    newView.z 
+= (cosTheta + (1 - cosTheta) * z * z)        * view.z;

    
/** 更新攝像機的方向 */
    m_View 
= m_Position + newView;
}



posted @ 2012-06-12 11:29 Jacc.Kim 閱讀(1768) | 評論 (0)編輯 收藏

     摘要: 下面這個地址,介紹了幾個c++中的關鍵字。還不錯,就收下了。http://m.shnenglu.com/leetaolion/archive/2011/09/13/46586.html C++關鍵字:mutable、volatile、explicit以及__based      mutable關鍵字     關鍵字mu...  閱讀全文
posted @ 2012-05-29 13:59 Jacc.Kim 閱讀(252) | 評論 (0)編輯 收藏

好久沒有寫博客了。這里記錄一點關于ccLayer的觸摸處理的記錄,怕將來忘記。
要使用ccLayer,必要要處理它的觸摸響應。否則就少了必要的交互。
關于ccLayer的觸摸有兩種類型。
1) 單點觸摸
2) 多點觸摸
下面分別總結一下:
1) 單點觸摸
要使用單點觸摸,必須要重寫以下幾個接口:
 virtual void onEnter();//必須
 virtual void onExit();//必須
 virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);//必須
 virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent);//可選,但一般情況下要
 virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);//可選,但一般情況下要
 virtual void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent);//可選
a) onEnter();接口。在此接口中,需要調用父類的該接口,并且最重要的,要為當前對象注冊一個觸摸委托(即:代理)。參考如下代碼:
 CCLayer::onEnter();
 CCTouchDispatcher::sharedDispatcher()->addTargetedDelegate(this, 0, true);
b) onExit();接口。在此接口中,需要將在onEnter()中注冊的當前對象的觸摸委托給移除掉。然后調用父類的onExit();。參考代碼如下:
 CCTouchDispatcher::sharedDispatcher()->removeDelegate(this);
 CCLayer::onExit();
c) ccTouchBegan();該接口,細心的人可能會發現,就它是返回bool的。它的返回值決定著,后續的ccTouchMoved();ccTouchEnded();ccTouchCancelled();是否觸發。只有返回true時才觸發。
關于ccTouchBegan();ccTouchMoved();ccTouchEnded();ccTouchCancelled();的作用,在此我就不多說了。看名字我想就應該能清楚。

2) 多點觸摸
要使用多點觸摸。則只需要實現重寫如下幾個接口,即可:
 virtual void ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent);
 virtual void ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent);
 virtual void ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent);
它們的作用我也不多說。下面簡要介紹下CCSet*對象。它存儲著所有的觸摸信息。即:遍歷它,可以處理所有的觸摸點響應。其他的用法同單點觸摸一樣。
注意:用多點觸摸時,不需要注冊上面第 1) 點中的a)與b)小點的信息。(如果我沒記錯的話,處理了,可能會讓程序蹦掉。)
posted @ 2012-04-11 12:08 Jacc.Kim 閱讀(5706) | 評論 (0)編輯 收藏

     摘要: 原文轉自:http://m.shnenglu.com/tx7do/archive/2006/04/24/6146.html TinyXml學習筆記張弛 <zhangchi@china.com>一、      TinyXml 的特點TinyXml 是一個基于 DOM ...  閱讀全文
posted @ 2012-02-14 17:40 Jacc.Kim 閱讀(365) | 評論 (0)編輯 收藏

CCDirector::sharedDirector()->getWinSize();
CCSprite::setPosition(...);
CCSprite::getPosition();

以上這些都是以 點 為單位的(不是像素)。
猜測:所有在cocos2d中有關x與y有關的,應該都是以點為單位。
posted @ 2012-02-01 09:48 Jacc.Kim 閱讀(381) | 評論 (0)編輯 收藏

1) 場景創建出來后,如果有autorelease。則在該場景被替換掉時,先前場景將被釋放。(這點在cc的管理器中有注釋說明)
2) 場景創建出來后,如果沒有autorelease。則在被添加進管理器后,請一定要release一次。否則將會有內存泄漏
posted @ 2012-01-18 10:31 Jacc.Kim 閱讀(472) | 評論 (0)編輯 收藏

1) CCMenuItem*對象在創建出來后并添加到CCMenu*對象后,只要CCMenu對象有釋放,CCMenuItem*對象也將被釋放。即:CCMenuItem*對象不需要再將釋放。。否則可能會蹦。
2) CCMenu*對象被addChild到父對象后,最后只要remove出來就可以。remove出來后,CCMenu*對象就被釋放掉。(原因:因為CCMenu*對象被創建出來時,它是autorelease()的)

 ccColor3B color;
 color.r = 0;
 color.g = 0;
 color.b = 255;
 m_pPlayMenuItem = CCMenuItemFont::itemFromString("Play", this, menu_selector(CWelcomeScene::OnPlayGameMenuItemClicked));
 ((CCMenuItemFont*)m_pPlayMenuItem)->setFontSizeObj(12);
 ((CCMenuItemFont*)m_pPlayMenuItem)->setColor(color);
 
 color.r = 255;
 color.g = 0;
 color.b = 0;
 m_pExitMenuItem = CCMenuItemFont::itemFromString("Exit", this, menu_selector(CWelcomeScene::OnExitMenuItemClicked));
 ((CCMenuItemFont*)m_pExitMenuItem)->setFontSizeObj(12);
 ((CCMenuItemFont*)m_pExitMenuItem)->setColor(color);

 if (NULL == m_pMenu)
 {
  m_pMenu = CCMenu::menuWithItems(m_pPlayMenuItem, m_pExitMenuItem, NULL);
  this->addChild(m_pMenu, 1);
  m_pMenu->alignItemsVerticallyWithPadding(0.0f);
 }


 m_pPlayMenuItem = CCMenuItemImage::itemFromNormalImage(g_pcszStartNormalMI, g_pcszStartSelectedMI, this, menu_selector(CWelcomeScene::OnPlayGameMenuItemClicked));
 m_pExitMenuItem = CCMenuItemImage::itemFromNormalImage(g_pcszCloseNormalMI, g_pcszCloseSelectedMI, this, menu_selector(CWelcomeScene::OnExitMenuItemClicked)); 
 m_pPlayMenuItem->setScale(0.4f);

 m_pMenu = CCMenu::menuWithItems(m_pPlayMenuItem, m_pExitMenuItem, NULL);
 this->addChild(m_pMenu, 1);

 float fX = GetCurrentWinSize(true).width / 2.0f - 10.0f;
 float fY = -(GetCurrentWinSize(false).height / 2.0f) + 5.0f;
 m_pExitMenuItem->setAnchorPoint(ccp(1.0, 0.0f));
 m_pExitMenuItem->setPosition(ccp(fX, fY));

 fX -= m_pExitMenuItem->getContentSize().width + 2.0f;
 fY -= 2.0f;
 m_pPlayMenuItem->setAnchorPoint(ccp(1.0f, 0.0f));
 m_pPlayMenuItem->setPosition(ccp(fX, fY));



posted @ 2012-01-18 10:25 Jacc.Kim 閱讀(806) | 評論 (1)編輯 收藏

僅列出標題
共14頁: First 5 6 7 8 9 10 11 12 13 Last 
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲黄色毛片| 亚洲人体偷拍| 国语自产精品视频在线看一大j8| 亚洲国产日韩欧美在线99| 先锋a资源在线看亚洲| 亚洲韩国一区二区三区| 中文精品99久久国产香蕉| 鲁鲁狠狠狠7777一区二区| 国产欧美日韩一区二区三区在线 | 亚洲一区二区免费视频| 欧美黄色小视频| 亚洲女同同性videoxma| 久久婷婷激情| 亚洲欧洲久久| 久久一二三国产| 在线观看亚洲视频| 久久综合网络一区二区| 久久九九国产精品| 韩国美女久久| 免费国产一区二区| 老司机免费视频久久| 亚洲高清二区| 亚洲国产精品毛片| 久久综合九色综合网站| 欧美激情在线观看| 亚洲私人黄色宅男| 欧美粗暴jizz性欧美20| 久久精品国产视频| 欧美激情 亚洲a∨综合| 亚洲欧美激情一区二区| 国产视频一区欧美| 日韩视频免费观看| 国产欧美日韩一级| 欧美一区二区三区免费在线看| 亚洲少妇最新在线视频| 久久人人97超碰精品888| 日韩视频在线一区二区三区| 欧美成人性生活| 日韩天堂在线观看| 一本一道久久综合狠狠老精东影业| 欧美视频你懂的| 久久精品中文字幕一区| 久久亚洲美女| 日韩视频国产视频| 99视频一区| 激情丁香综合| 欧美第一黄色网| 99这里只有精品| 国产农村妇女毛片精品久久麻豆| 久久久噜噜噜久久人人看| 米奇777超碰欧美日韩亚洲| 夜夜嗨av一区二区三区四季av| 亚洲天堂成人在线观看| 亚洲乱码国产乱码精品精天堂 | 欧美一区二区免费| 久久久久久久久久久成人| 亚洲精品一区二| 香蕉免费一区二区三区在线观看| 最新国产精品拍自在线播放| 亚洲最新合集| 午夜电影亚洲| 日韩一区二区电影网| 亚洲欧美视频一区二区三区| 亚洲欧洲一区| 欧美在线播放| 欧美一级大片在线观看| 欧美区高清在线| 久久午夜精品| 欧美伊人久久久久久久久影院 | 男男成人高潮片免费网站| 久久久国产精品一区| 欧美成人精品在线观看| 亚洲图片欧美日产| 激情久久久久久久久久久久久久久久| 欧美日韩mp4| 亚洲欧美日韩一区二区| 欧美专区亚洲专区| 亚洲欧美在线磁力| 久久精品国产综合| 亚洲香蕉视频| 亚洲精品色婷婷福利天堂| 激情五月综合色婷婷一区二区| 亚洲免费视频一区二区| 久久国产精品久久久久久电车 | 亚洲欧美综合精品久久成人| 麻豆精品一区二区av白丝在线| 亚洲国产精品久久久| 亚洲激情一区| av成人免费在线| 亚洲欧美成人一区二区在线电影 | 欧美视频不卡| 91久久极品少妇xxxxⅹ软件| 欧美激情第六页| 一区在线观看视频| 久久久久免费| 麻豆av一区二区三区| 亚洲欧洲综合另类| 99av国产精品欲麻豆| 在线欧美三区| 久久久久久久尹人综合网亚洲 | 亚洲电影第1页| 亚洲国产成人一区| 欧美一区二区精品久久911| 欧美激情视频在线播放| 国内免费精品永久在线视频| 一区二区日韩伦理片| 久久综合网色—综合色88| 午夜精品成人在线视频| 欧美日韩午夜剧场| 一区二区三区四区国产精品| 欧美福利电影网| 国产视频观看一区| 欧美精品色综合| 亚洲美女区一区| 日韩视频免费看| 黄色日韩网站| 欧美成人按摩| 欧美日韩国产在线播放网站| 国产精品高潮在线| 亚洲一区二区精品在线| 欧美午夜在线观看| 亚洲欧美www| 欧美成人精品h版在线观看| 亚洲国产一区二区三区a毛片| 欧美福利影院| 亚洲先锋成人| 久久综合九色综合欧美就去吻| 在线日韩中文字幕| 欧美日韩天天操| 欧美中文字幕视频在线观看| 亚洲国产精品毛片| 亚洲欧美电影在线观看| 激情国产一区二区| 欧美三级视频| 久久久久一区二区三区| 亚洲电影免费观看高清| 亚洲综合日本| 在线播放日韩| 国产精品xnxxcom| 美女主播一区| 亚洲欧美在线视频观看| 在线观看成人av电影| 欧美日韩国产成人在线观看| 午夜精品久久久久久久99黑人 | 99re热这里只有精品免费视频| 欧美一级理论片| 亚洲欧洲日产国产网站| 国产欧美日韩精品丝袜高跟鞋| 欧美顶级大胆免费视频| 小处雏高清一区二区三区| 亚洲国内精品在线| 久久精品国亚洲| 亚洲欧美视频在线观看| 亚洲国产精品第一区二区| 国产精品久久影院| 欧美裸体一区二区三区| 久久精品视频在线| 亚洲香蕉视频| 日韩性生活视频| 亚洲大片在线观看| 久久精品亚洲国产奇米99| 国产精品女主播在线观看| 欧美自拍偷拍| 欧美激情网友自拍| 国产视频在线观看一区| 国产精品v日韩精品| 久久先锋影音av| 亚洲欧美bt| 亚洲在线免费| 亚洲精选一区二区| 国产精品国产三级国产普通话三级| 亚洲国产女人aaa毛片在线| 久久激情视频| 欧美一区二区视频免费观看 | 六十路精品视频| 久久久精品日韩| 午夜精品av| 亚洲欧美精品suv| 亚洲与欧洲av电影| 宅男噜噜噜66国产日韩在线观看| 亚洲激情在线观看视频免费| 欲色影视综合吧| 亚洲国产精品va在线看黑人动漫| 国产视频一区在线| 国外成人在线视频网站| 国产综合网站| 国产在线不卡精品| 黄色在线一区| 亚洲国产精品视频| 亚洲国产视频一区二区| 亚洲精品一区二区三区av| 亚洲精品一线二线三线无人区| 亚洲精品少妇30p| 亚洲午夜精品一区二区三区他趣| 亚洲午夜久久久久久久久电影网| 99精品国产高清一区二区| 在线亚洲+欧美+日本专区| 亚洲嫩草精品久久| 久久精品系列| 亚洲国产精品一区二区三区|