PIXNET Logo登入

太陽系後援會

跳到主文

部落格全站分類:職場甘苦

  • 相簿
  • 部落格
  • 留言
  • 名片
  • 4月 28 週三 201015:24
  • 求整數以2為底的Log運算

實在懶得打字…,反正結論就是我用3.,就這樣XD
 
1. x越大, 則迴圈執行次數越多, 效能隨x變動
int IntLog2(unsigned int x)
{
    int r = 0;
    while (x > 1)
    {
       x >>= 1;
       ++r;
    }
    return r;
}
(繼續閱讀...)
文章標籤

kgsprogrammer 發表在 痞客邦 留言(2) 人氣(741)

  • 個人分類:C++
▲top
  • 2月 07 週六 200914:25
  • Overload + Overwrite + Virtual = ???

前幾天發現一個很有趣的問題
至今仍然找不到解答
歡迎高手們來挑戰
 
(繼續閱讀...)
文章標籤

kgsprogrammer 發表在 痞客邦 留言(3) 人氣(438)

  • 個人分類:C++
▲top
  • 1月 14 週三 200913:49
  • % 運算子的妙用

% 運算子是求餘數的運算子在二維陣列的處理可以使用此技巧
首先看以下的範例
int Array[M][N];
for (int i = 0; i < M; ++i)
    for (int j = 0; j < N; ++j)
        scanf("%d", &Array[i][j]);
(繼續閱讀...)
文章標籤

kgsprogrammer 發表在 痞客邦 留言(0) 人氣(179)

  • 個人分類:C++
▲top
  • 1月 03 週六 200920:37
  • X % 2^N 特定數值的取餘數計算

% 在C當中為取餘數(Mod)
Ex:
5 % 2 = 1
12 % 4 = 0
(繼續閱讀...)
文章標籤

kgsprogrammer 發表在 痞客邦 留言(1) 人氣(2,969)

  • 個人分類:C++
▲top
  • 8月 09 週六 200813:13
  • #,##的功能


# 和 ##這兩個是個非常好用的前置定義語法,通常搭配#define出現
1. #的用途是將啣接的符號轉換成字串
example
#define to_string(s) #s
使用方法
cout << to_string(Hello World!) << endl;
看清楚,Hello World並沒有"",因此它並不是字串,但是透過定義的巨集to_string可以將Hello World!符號轉換為字串。
以上程式片斷等於
cout << "Hello World!" << endl;
2. ##的用是將兩個程式片斷合併
example
#define concatenate( x, y) x##y
....
int xy = 10;
....
cout << concatenate( x, y) << endl;
等同於
cout << xy << endl;
##,#的功能太強大了,這裡實在說不清楚,畢竟要實作時才能體會它的強大威力
大家有興趣可以去看RTTI2部曲有用到##與#這兩個強大功能
至於其他使用的地方,就請大家仔細看看以後發的文章吧
讓我們一起大喊
彼得哥萬歲~~~~~~~~
(繼續閱讀...)
文章標籤

kgsprogrammer 發表在 痞客邦 留言(0) 人氣(113)

  • 個人分類:C++
▲top
  • 8月 07 週四 200823:43
  • RTTI 二部曲


上一篇提到如何去使用C++函式庫所內建的RTTI操作方式,
但是怎麼自己設計一個還是有點霧煞煞是吧。
沒關係,奉彼德哥之命,我又看了一些書,爬了一些文章。
現在就來跟各位娓娓道來這些心路歷程。
要怎麼設計RTTI?
想想看,如果你要查字典,是不是要先知道部首,部首不知道,你還可以查注音,不會唸的話查筆畫總可以吧。
部首,注音,筆畫你可以想像成索引,索引到的地方就是字詞的解釋(好久沒查字典了,老實說,都快忘記怎麼查了)。
如此,當我們要建立RTTI的資料庫的時候,當類別被建構起來的時候紀錄必要的資訊。
怎麼樣,聽起來很簡單吧。
如果就這樣結束,我應該會被彼得哥的大鎖打死。
來,首先我們需要一個資料結構來儲存類別型錄。
其中至少要有char *來表示類別名稱,一個Next指向下一個,一個First指向第一個,由於First只需要有一個,所以用static來修飾。
class CRTTIClass
{
public:
    char * m_pcClassName;
    int        m_iObjectSize;
    UINT  m_uiSchema;
    CObject * (PASCAL * m_pfnCreateObject) ();
    CRTTIClass * m_pBaseClass;
    static CRTTIClass * ms_pFirstClass;
    CRTTIClass * m_pNextClass;
}
記得要對ms_pFirstClass做初始化
CRTTIClass * CRTTIClass::ms_pFirstClass = NULL;
再來
為了要讓每一個class都能夠有這個CRTTIClass,間單的方式就是在每個class都有這個CRTTIClass的instance,但是這樣每個class都要再寫對每個CRTTIClass設定的動作。想一想,這真的是一件麻煩的事。
因此,我們使用巨集來完成這項工作
定義以下巨集
#define DECLARE_DYNAMIC(class_name) \
public:
    static CRTTIClass class##class_name;  \
    virtual CRTTIClass * GetRTTIClass() const;
如此你只要使用此巨集
    DECLARE_DYNAMIC(CA);
編譯器會幫你展開為
    public:
        static CRTTIClass classCA;
        virtual CRTTIClass * GetRTTIClass() const;
這樣還沒完
我們只完成宣告而已,設定與連結的動作當然也要神不知鬼不覺的做完才可以
再來定義一個巨集
#define IMPLEMENT_DYNAMIC(class_name, base_class_name) \
    _IMPLEMENT_RTTICLASS(class_name, base_class_name, 0xFFFF, NULL)
#define _IMPLEMENT_RTTICLASS(class_name, base_class_name, wSchema, pfnNew) \
    static char _lpsz##class_name[] = #class_name; \
    CRTTIClass class_name::class##class_name = {\
        _lpsz##class_name, sizeof(class_name), wSchema, pfnNew, \
        RUNTIME_CLASS(base_class_name), NULL }; \
    static AFX_CLASSINT _int_##class_name(&class_name::class##class_name); \
    CRTTIClass * class_name::GetRTTIClass() const \
     { return &class_name::class##class_name; } \
在這裡又有一個RUNTIME_CLASS巨集,定義如下
#define RUNTIME_CLASS(class_name) \
    (&class_name::class##class_name)
其中更有一個重要的東西存在,就是AFX_CLASSINT這個struct,它負責linked list的串接工作
所以還必須宣告並定義AFX_CLASSINT
struct AFX_CLASSINT
{
    AFX_CLASSINT(CRTTIClass * pNewClass);
}
C++的struct可以有建構子與解構子
AFX_CLASSINT::AFX_CLASSINT(CRTTIClass * pNewClass)
{
    pNewClass->m_pNextClass = CRTTIClass::ms_pFirstClass;
    CRTTIClass::ms_pFirstClass = pNewClass;
}
接下來看一下範例
class CChild : public CBase
{
    //在類別內宣告
    DECLARE_DYNAMIC(CChild)
};
//在類別外宣告
IMPLEMENT_DYNAMIC(CChild, CBase)
上面的程式就會展開為
class CChild : public CBase
{
public:
    static CRTTIClass classCChild;
    virtual CRTTIClass * GetRTTIClass() const;
};
static char _lpszCChild[] = "CChild";
CRTTIClass CChild::classCChild = {
    _lpszCChild, sizeof(CChild), OxFFFF, NULL,
    &CBase::classCBase, NULL };
static AFX_CLASSINT _int_CChild(&CChild::classCChild);
CRTTIClass * CChild::GetRTTIClass() const
{ return &CChild::classCChild; }
如此複雜的工作就讓巨集給做完了,如此就不需要每個class都打一堆Code了
但是,串列的頭總是需要特別的處理。
class CBase
{
public:
    static CRTTIClass classCBase;
    virtual CRTTIClass * GetRTTIClass() const;
}
static char lpszCChild[] = "CBase";
struct CRTTIClass CBase::classCBase = 
{ lpszCChild, sizeof(CBase), 0xFFFF, NULL, NULL };
static AFX_CLASSINT _int_CBase(&CBase::classCBase);
CRTTIClass * CBase::GetRTTIClass() const
{
    return &CBase::classCBase;
}
聰明的你一定也看出來這些落落長的程式碼也可以用巨集來完成,如果你只有一個Root的class那你是可以不必設計一個專為root宣告RTTI的巨集,但是你如果想要很多種類別型錄,那麼設計一個給root使用的巨集是在所難免的,這就交給你們設計啦,希望彼得哥不會打我。
如此類別型錄已經都設計好了,但總覺得少了什麼
對了!!!!!!
就是IsKindOf
有類別型錄但是沒有查表的方式,這要叫別人怎麼查阿
奉彼得哥之命,馬上補上IsKindOf
IsKindOf要怎麼設計呢?左思右想之下,想到一個偷懶的方法
請看以下範例
CBase
{
public:
    .....................
    .....................
    bool IsKindOf(const CRTTIClass * pClass) const;
};
bool CBase::IsKindOf(const CRTTIClass * pClass) const
{
    CRTTIClass * pClassThis = GetRTTIClass();
    while (pClassThis != NULL)
    {
        if (pClassThis = pClass)
            return true;
        pClassThis = pClassThis->m_pBaseClass;
    }
    return false;
}
IsKindOf就是再檢查某個物件是不是某一個物件的延伸,所以他追查的方式是同宗查詢
聰明的你一定也看出來它可以設計為巨集,並且設計在宣告root的RTTI巨集裡。
有些人會覺得這些使用的方式很眼熟,沒錯它就是MFC裡的RTTI
但這不是我們的主要探討所在,最重要的是讓一般人能夠理解RTTI的設計原理
有什麼問題記得要問彼得哥喔
讓我們一起大喊
彼得哥萬歲~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
(繼續閱讀...)
文章標籤

kgsprogrammer 發表在 痞客邦 留言(0) 人氣(287)

  • 個人分類:C++
▲top
  • 8月 04 週一 200800:30
  • RTTI

RTTI是什麼?做這些有什麼意義?
呜
~~我想,很多programmer對這個既熟悉又充滿陌生的辭彙感到一知半解。
熟悉的地方是,每天都要用它。引擎裡有用到,就算引擎沒有,對於一個專業的物件導向程式設計師來說,
RTTI是不可或缺的,畢竟設計一個class就是在宣告一個型別(Type)。陌生的地方是,很多人都會用(因為有人已經寫好了,只要call function就好),但是卻不了解怎麼做,一個programmer怎麼可以對技術一知半解,這要怎麼生存。寫這邊文章的最主要目標就是分享我對RTTI研究的心得,希望也能夠帶給大家許多幫助,我會用連小學五年級都懂的話來告訴大家。
RTTI(Run-Time Type Information, or Run-Time Type Identification)
執行時期型態資訊(辨識),C++可以將基礎類別指向衍生類別,這通常發生在程式執行時,因此你並不知道這個基礎類別指向的物件型態是什麼,如此就必須在執行時期才可以做到取得物件資訊的,瞭解物件的資訊之後才能做正確的操作。那要怎麼做呢?

最簡單的方法就是使用
typeid和dynamic_cast
這裡先簡單說明一下dynamic_cast。

dynamic_cast是C++的動態型別轉換機制,簡單來說就是在執行時期安全的將指標(pointer)或是參考(reference)轉換到衍生類別。首先會確認轉換目標與來源是否屬同一個類別階層,當轉換的是指標時,成功時回傳記憶體位址,失敗則回傳NULL,如果轉換的是參考,失敗則會丟出一個bad_cast。
if (A * pA = dynamic_cast<A *>(pBase))
{
    //轉型成功
    pA->OK();
}
try
{
    A & rA = dynamic_cast<A &>(rBase);
    rA.OK();
}
catch(std::bad_cast)
{
    //轉型失敗
}
typeid就是產生指標或是參考所實際指向的物件的資訊結構
type_info
typeid表示式:
    typeid(exp);
exp的意思是類別的指標或是參考,或是其類別名稱。typeid傳回的是一個type_info的物件參考。
type_info:

class type_info {
public:
    virtual ~type_info();
    bool operator==(const type_info& rhs) const;
    bool operator!=(const type_info& rhs) const;
    int before(const type_info& rhs) const;
    const char* name() const;
    const char* raw_name() const;
};
你無法直接instance type_info這個類別,因為此類別只有一個私有的複製建構子,你也無法用assignment來建立,因為assignment operator也是私有的。你只能透過typeid這個function來建立。
==, !=運算子顧名思義就是判斷該type_info是否和其他的type_info相同。
name這個member function回傳一個人類可以看的懂的字串來顯示該指標指向之類別名稱。
raw_name說的就是一個原始的名字,也就是在記憶體裡存放的資料,這表示我們一般人是看不懂的(因該只有受過專業的訓練才看的懂吧)。但是它比name快,因為name就是把這些資料轉換成我們看的懂的文字。不過一般人是不會用raw_name的。
用法很簡單,請看下面。
if (typeid(pBase) == typeid(A))
{
    //pBase指向的是A
    A * pA = dynamic_cast<A *>(pBase);
    pA->OK();
}
if (typeid(pA) == typeid(pB))
{
    //兩個pointer是相同的class
}
cout << typeid(pA).name();
以上就是RTTI的基本知識,另外一點要提的就是
要使用RTTI,你必須inlcude <typeinfo>這個header file
在VC++的專案設定裡C/C++ --> Language --> Enable Run-Time Type Info設定為
Yes (/GR)
就先寫到這裡吧
下一回在跟大家更深入的談RTTI

(繼續閱讀...)
文章標籤

kgsprogrammer 發表在 痞客邦 留言(0) 人氣(722)

  • 個人分類:C++
▲top
  • 8月 02 週六 200815:45
  • inline function是做什麼的

inline function是C++程式碼在編譯時嵌入呼叫者所在之處的函數。就像巨集一樣,inline function免除了函數呼叫時的而外負擔,增加效率,並且可以讓編譯器對其最佳化(procedural integration)。與macro不同的地方是,inline function只會對所有引數求一次的值,避免某些當在寫macro所不易察覺的錯誤。次外,inline function還會檢測引數的型態,做必要的型別轉換。
注意:過度使用inline function會讓程式碼過於肥胖,於分頁(paging)環境下反而有負面的效能影響。
宣告
1.
    inline void function(int i, float f);
    
2.
    class C
    {
    public:
        inline void functionA(int i);
        void functionB(int i);
    };
    
    inline void functionB(int i) //實做函式時加上inline也是可以的
    {
    }
此外,在debug版本的編譯器是不會將inline function展開的,我想應該是為了能夠在除錯時trace程式碼。
在以下網址有談到很多關於inline function的知識,給大家參考
http://miloyip.seezone.net/?p=47
(繼續閱讀...)
文章標籤

kgsprogrammer 發表在 痞客邦 留言(0) 人氣(8,508)

  • 個人分類:C++
▲top
1

自訂側欄

個人頭像

kgsprogrammer
暱稱:
kgsprogrammer
分類:
職場甘苦
好友:
累積中
地區:

近期文章

  • 輕鬆愜意,沁涼消暑----轉吧!流麵
  • Hook 4 Fun ---- 終極派對遊戲
  • Design Pattern -- Observer
  • Design Pattern -- Strategy
  • Template
  • Shaders for Game Programmers and Artists--Chap1_welcome to the world of shaders (閱讀心得)
  • 基本演算法分析
  • 『The Making of God of War III』讀後雜談
  • 求整數以2為底的Log運算
  • 很有台灣味的國產元創iPhone, iPod Touch遊戲----Sliding War

文章彙整

文章分類

toggle 程式研究 (6)
  • Design Pattern (2)
  • Refactory (8)
  • AI (2)
  • 3D圖學 (4)
  • 程式設計 (7)
  • C++ (8)
toggle 遊戲研究 (3)
  • 遊戲設計 (5)
  • 遊戲新聞 (7)
  • 遊戲開發 (4)
toggle 閒聊八卦 (1)
  • 閒聊八卦 (4)
toggle 後援會 (1)
  • 後援會公告 (1)
toggle 彼得哥的生平事蹟 (1)
  • 名言錦句篇 (1)
  • Game Develepment (2)
  • C++ (3)
  • 未分類文章 (1)

部落格文章搜尋

誰來我家

參觀人氣

  • 本日人氣:
  • 累積人氣: