去年我作了一個Lua腳本的C++包裝,有許多朋友感興趣,并嘗試使用,我感到受寵若驚。事實上,我作的包裝,學習的目的比較強,它還是有許多缺陷的。為了讓朋友們少走彎路,我推薦使用LuaPlus作為C++的包裝。
LuaPlus是Lua的C++增強,也就是說,LuaPlus本身就是在Lua的源碼上進行增強得來的。用它與C++進行合作,是比較好的一個選擇。
LuaPlus目前版本為:LuaPlus for Lua 5.01 Distribution Build 1080 (February 28, 2004)。大家可以到http://luaplus.org/ 站點下載:
源碼 (http://wwhiz.com/LuaPlus/LuaPlus50_Build1081.zip)
目標碼 (http://wwhiz.com/LuaPlus/LuaPlus50_Build1081_Win32Binaries.zip)
我將在下面說明,如何使用LuaPlus,以及如何更方便的讓LuaPlus與C++的類合作無間。
1. 調用Lua腳本
// 創建Lua解釋器:
LuaStateOwner state;
// 執行Lua腳本:
state->DoString("print('Hello World\n')");
// 載入Lua腳本文件并執行:
state->DoFile("C:\\test.lua");
// 載入編譯后的Lua腳本文件并執行:
state->DoFile("C:\\test.luac");
2. 與Lua腳本互相調用
// 為Lua腳本設置變量
state->GetGlobals().SetNumber("myvalue", 123456);
// 獲得Lua變量的值
int myvalue = state->GetGlobal("myvalue").GetInteger();
// 調用Lua函數
LuaFunction<int> luaPrint = state->GetGlobal("print");
luaPrint("Hello World\n");
// 讓Lua調用C語言函數
int add(int a, int b){ return a+b;}
state->GetGlobals().RegisterDirect("add", add);
state->DoString("print(add(3,4))");
// 讓Lua調用C++類成員函數
class Test{public: int add(int a, int b){return a+b;}};
Test test;
state->GetGlobals().RegisterDirect("add", test, add);
state->DoString("print(add(3,4))");
3. 在Lua腳本中使用C++類
這個稍微有點小麻煩。不過,我包裝了一個LuaPlusHelper.h的文件,它可以很輕松的完成這個工作。它的實現也很簡單,大家可以從源碼上來獲得如何用純LuaPlus實現同樣的功能。
不過,這里仍然有一個限制沒有解決:不能使用虛成員函數。不過考慮到我們僅是在Lua調用一下C++函數,并不是要將C++完美的導入到Lua,這個限制完全可以接受。
另外,類成員變量不能直接在Lua中訪問,可以通過類成員函數來訪問(比如SetValue/GetValue之類)。
// 下面是一個簡單的C++類:
class Logger
{
public:
void LOGMEMBER(const char* message)
{
printf("In member function: %s\n", message);
}
Logger()
{
printf("Constructing(%p)...\n", this);
v = 10;
}
virtual ~Logger()
{
printf("Destructing(%p)...\n", this);
}
Logger(int n)
{
printf(" -- Constructing[%d](%p)...\n", n, this);
}
Logger(Logger* logger)
{
printf(" -- Constructing[%p](%p)...\n", logger, this);
logger->LOGMEMBER(" Call From Constructor\n");
}
int SetValue(int val)
{
v = val;
}
int GetValue()
{
return v;
}
public:
int v;
};
// 導入到Lua腳本:
LuaClass<Logger>(state)
.create("Logger") // 定義構造函數 Logger::Logger()
.create<int>("Logger2") // 定義構造函數 Logger::Logger(int)
.create<Logger*>("Logger3") // 定義構造函數 Logger::Logger(Logger*)
.destroy("Free") // 定義析構函數 Logger::~Logger()
.destroy("__gc") // 定義析構函數 Logger::~Logger()
.def("lm", &Logger::LOGMEMBER) // 定義成員函數 Logger::LOGMEMBER(const char*)
.def("SetValue", &Logger::SetValue)
.def("GetValue", &Logger::GetValue);
// 在Lua中使用Logger類(1):
state->DoString(
"l = Logger();" // 調用構造函數 Logger::Logger()
"l.lm('Hello World 1');" // 調用成員函數 Logger::LOGMEMBER(const char*)
"l.Free();" // 調用析構函數 Logger::~Logger()
);
// 在Lua中使用Logger類(2):
state->DoString(
"m = Logger(10);" // 調用構造函數 Logger::Logger(int)
"m.lm('Hello World 2');" // 調用成員函數 Logger::LOGMEMBER(const char*)
"n = Logger(m);" // 調用構造函數 Logger::Logger(Logger*)
"n.lm('Hello World 3');" // 調用成員函數 Logger::LOGMEMBER(const char*)
"m.SetValue(11);"
"print(m.GetValue());"
"m,n = nil, nil;" // m,n 將由Lua的垃極回收來調用析構函數
);
4. 將一組C函數歸類到Lua模塊
//同上面一樣,我采用LuaPlusHelper.h來簡化:
LuaModule(state, "mymodule")
.def("add", add)
.def("add2", test, add);
state->DoString(
"print(mymodule.add(3,4));"
"print(mymodule.add2(3,4));"
);
5. 使用Lua的Table數據類型
// 在Lua中創建Table
LuaObject table = state->GetGlobals().CreateTable("mytable");
table.SetInteger("m", 10);
table.SetNumber("f", 1.99);
table.SetString("s", "Hello World");
table.SetWString("ch", L"你好");
table.SetString(1, "What");
// 相當于Lua中的:
// mytable = {m=10, f=1.99, s="Hello World", ch=L"你好", "What"}
// 也可以使用table作為key和value:
state->GetGlobals().CreateTable("nexttable")
.SetString(table, "Hello")
.SetObject("obj", table);
// 相當于Lua中的:
// nexttable = {mytable="Hello", obj=mytable}
//獲得Table的內容:
LuaObject t2 = state->GetGlobals("mytable");
int m = t2.GetByName("m").GetInteger();
LuaObject t3 = state->GetGlobals("nexttable");
std::string str = t3.GetByObject(t2).GetString();
6 遍歷Table
LuaStateOwner state;
state.DoString( "MyTable = { Hi = 5, Hello = 10, Yo = 6 }" );
LuaObject obj = state.GetGlobals()[ "MyTable" ];
for ( LuaTableIterator it( obj ); it; it.Next() )
{
const char* key = it.GetKey().GetString();
int num = it.GetValue().GetInteger();
}
篇尾
上面我只是簡單的舉一些例子來說明LuaPlus以及LuaPlusHelper的使用方法,具體文檔請參見LuaPlus。
需要下載LuaPlusHelper,請點這里:
http://www.d2-life.com/LBS/attachments/month_200509/06_zwo3LuaPlusHelper.zip
作者: 沐楓 (第二人生成員)
版權所有轉載請注明原出處
主頁:第二人生
http://www.d2-life.com http://www.d2-life.com/LBS/blogview.asp?logID=39 在這篇文章中,我想向大家介紹如何進行Lua程序設計。我假設大家都學過至少一門編程語言,比如Basic或C,特別是C。因為Lua的最大用途是在宿主程序中作為腳本使用的。
Lua 的語法比較簡單,學習起來也比較省力,但功能卻并不弱。
在Lua中,一切都是變量,除了關鍵字。請記住這句話。
I. 首先是注釋
寫一個程序,總是少不了注釋的。
在Lua中,你可以使用單行注釋和多行注釋。
單行注釋中,連續兩個減號"--"表示注釋的開始,一直延續到行末為止。相當于C++語言中的"http://"。
多行注釋中,由"--[["表示注釋開始,并且一直延續到"]]"為止。這種注釋相當于C語言中的"/*…*/"。在注釋當中,"[["和"]]"是可以嵌套的。
II. Lua編程
經典的"Hello world"的程序總是被用來開始介紹一種語言。在Lua中,寫一個這樣的程序很簡單:
print("Hello world")
在Lua中,語句之間可以用分號";"隔開,也可以用空白隔開。一般來說,如果多個語句寫在同一行的話,建議總是用分號隔開。
Lua 有好幾種程序控制語句,如:
條件控制:if 條件 then … elseif 條件 then … else … end
While循環:while 條件 do … end
Repeat循環:repeat … until 條件
For循環:for 變量 = 初值,終點值,步進 do … end
For循環:for 變量1,變量2,… ,變量N in表或枚舉函數 do … end
注意一下,for的循環變量總是只作用于for的局部變量,你也可以省略步進值,這時候,for循環會使用1作為步進值。
你可以用break來中止一個循環。
如果你有程序設計的基礎,比如你學過Basic,C之類的,你會覺得Lua也不難。但Lua有幾個地方是明顯不同于這些程序設計語言的,所以請特別注意。
.語句塊
語句塊在C++中是用"{"和"}"括起來的,在Lua中,它是用do 和 end 括起來的。比如:
do print("Hello") end
你可以在 函數 中和 語句塊 中定局部變量。
.賦值語句
賦值語句在Lua被強化了。它可以同時給多個變量賦值。
例如:
a,b,c,d=1,2,3,4
甚至是:
a,b=b,a -- 多么方便的交換變量功能啊。
在默認情況下,變量總是認為是全局的。假如你要定義局部變量,則在第一次賦值的時候,需要用local說明。比如:
local a,b,c = 1,2,3 -- a,b,c都是局部變量
.數值運算
和C語言一樣,支持 +, -, *, /。但Lua還多了一個"^"。這表示指數乘方運算。比如2^3 結果為8, 2^4結果為16。
連接兩個字符串,可以用".."運處符。如:
"This a " .. "string." -- 等于 "this a string"
.比較運算
< > <= >= == ~=
分別表示 小于,大于,不大于,不小于,相等,不相等
所有這些操作符總是返回true或false。
對于Table,Function和Userdata類型的數據,只有 == 和 ~=可以用。相等表示兩個變量引用的是同一個數據。比如:
a={1,2}
b=a
print(a==b, a~=b) -- true, false
a={1,2}
b={1,2}
print(a==b, a~=b) -- false, true
.邏輯運算
and, or, not
其中,and 和 or 與C語言區別特別大。
在這里,請先記住,在Lua中,只有false和nil才計算為false,其它任何數據都計算為true,0也是true!
and 和 or的運算結果不是true和false,而是和它的兩個操作數相關。
a and b:如果a為false,則返回a;否則返回b
a or b:如果 a 為true,則返回a;否則返回b
舉幾個例子:
print(4 and 5) --> 5
print(nil and 13) --> nil
print(false and 13) --> false
print(4 or 5) --> 4
print(false or 5) --> 5
在Lua中這是很有用的特性,也是比較令人混洧的特性。
我們可以模擬C語言中的語句:x = a? b : c,在Lua中,可以寫成:x = a and b or c。
最有用的語句是: x = x or v,它相當于:if not x then x = v end 。
.運算符優先級,從高到低順序如下:
^
not - (一元運算)
* /
+ -
..(字符串連接)
< > <= >= ~= ==
and
or
III. 關鍵字
關鍵字是不能做為變量的。Lua的關鍵字不多,就以下幾個:
and break do else elseif
end false for function if
in local nil not or
repeat return then true until while
IV. 變量類型
怎么確定一個變量是什么類型的呢?大家可以用type()函數來檢查。Lua支持的類型有以下幾種:
Nil 空值,所有沒有使用過的變量,都是nil。nil既是值,又是類型。
Boolean 布爾值
Number 數值,在Lua里,數值相當于C語言的double
String 字符串,如果你愿意的話,字符串是可以包含'\0'字符的
Table 關系表類型,這個類型功能比較強大,我們在后面慢慢說。
Function 函數類型,不要懷疑,函數也是一種類型,也就是說,所有的函數,它本身就是一個變量。
Userdata 嗯,這個類型專門用來和Lua的宿主打交道的。宿主通常是用C和C++來編寫的,在這種情況下,Userdata可以是宿主的任意數據類型,常用的有Struct和指針。
Thread 線程類型,在Lua中沒有真正的線程。Lua中可以將一個函數分成幾部份運行。如果感興趣的話,可以去看看Lua的文檔。
V. 變量的定義
所有的語言,都要用到變量。在Lua中,不管你在什么地方使用變量,都不需要聲明,并且所有的這些變量總是全局變量,除非,你在前面加上"local"。
這一點要特別注意,因為你可能想在函數里使用局部變量,卻忘了用local來說明。
至于變量名字,它是大小寫相關的。也就是說,A和a是兩個不同的變量。
定義一個變量的方法就是賦值。"="操作就是用來賦值的
我們一起來定義幾種常用類型的變量吧。
A. Nil
正如前面所說的,沒有使用過的變量的值,都是Nil。有時候我們也需要將一個變量清除,這時候,我們可以直接給變量賦以nil值。如:
var1=nil -- 請注意 nil 一定要小寫
B. Boolean
布爾值通常是用在進行條件判斷的時候。布爾值有兩種:true 和 false。在Lua中,只有false和nil才被計算為false,而所有任何其它類型的值,都是true。比如0,空串等等,都是true。不要被C語言的習慣所誤導,0在Lua中的的確確是true。你也可以直接給一個變量賦以Boolean類型的值,如:
varboolean = true
C. Number
在Lua中,是沒有整數類型的,也不需要。一般情況下,只要數值不是很大(比如不超過100,000,000,000,000),是不會產生舍入誤差的。在很多CPU上,實數的運算并不比整數慢。
實數的表示方法,同C語言類似,如:
4 0.4 4.57e-3 0.3e12 5e+20
D. String
字符串,總是一種非常常用的高級類型。在Lua中,你可以非常方便的定義很長很長的字符串。
字符串在Lua中有幾種方法來表示,最通用的方法,是用雙引號或單引號來括起一個字符串的,如:
"This is a string."
和C語言相同的,它支持一些轉義字符,列表如下:
\a bell
\b back space
\f form feed
\n newline
\r carriage return
\t horizontal tab
\v vertical tab
\\ backslash
\" double quote
\' single quote
\[ left square bracket
\] right square bracket
由于這種字符串只能寫在一行中,因此,不可避免的要用到轉義字符。加入了轉義字符的串,看起來實在是不敢恭維,比如:
"one line\nnext line\n\"in quotes\", 'in quotes'"
一大堆的"\"符號讓人看起來很倒胃口。如果你與我有同感,那么,我們在Lua中,可以用另一種表示方法:用"[["和"]]"將多行的字符串括起來,如:
page = [[
<HTML>
<HEAD>
<TITLE>An HTML Page</TITLE>
</HEAD>
<BODY>
<A HREF="
lua' target=_blank>
http://www.lua.org">Lua</A> [[a text between double brackets]]
</BODY>
</HTML>
]]
值得注意的是,在這種字符串中,如果含有單獨使用的"[["或"]]"就仍然得用"\["或"\]"來避免歧義。當然,這種情況是極少會發生的。
E. Table
關系表類型,這是一個很強大的類型。我們可以把這個類型看作是一個數組。只是C語言的數組,只能用正整數來作索引;在Lua中,你可以用任意類型來作數組的索引,除了nil。同樣,在C語言中,數組的內容只允許一種類型;在Lua中,你也可以用任意類型的值來作數組的內容,除了nil。
Table的定義很簡單,它的主要特征是用"{"和"}"來括起一系列數據元素的。比如:
T1 = {} -- 定義一個空表
T1[1]=10 -- 然后我們就可以象C語言一樣來使用它了。
T1["John"]={Age=27, Gender="Male"}
這一句相當于:
T1["John"]={} -- 必須先定義成一個表,還記得未定義的變量是nil類型嗎
T1["John"]["Age"]=27
T1["John"]["Gender"]="Male"
當表的索引是字符串的時候,我們可以簡寫成:
T1.John={}
T1.John.Age=27
T1.John.Gender="Male"
或
T1.John{Age=27, Gender="Male"}
這是一個很強的特性。
在定義表的時候,我們可以把所有的數據內容一起寫在"{"和"}"之間,這樣子是非常方便,而且很好看。比如,前面的T1的定義,我們可以這么寫:
T1=
{
10, -- 相當于 [1] = 10
[100] = 40,
John= -- 如果你原意,你還可以寫成:["John"] =
{
Age=27, -- 如果你原意,你還可以寫成:["Age"] =27
Gender=Male -- 如果你原意,你還可以寫成:["Gender"] =Male
},
20 -- 相當于 [2] = 20
}
看起來很漂亮,不是嗎?我們在寫的時候,需要注意三點:
第一,所有元素之間,總是用逗號","隔開;
第二,所有索引值都需要用"["和"]"括起來;如果是字符串,還可以去掉引號和中括號;
第三,如果不寫索引,則索引就會被認為是數字,并按順序自動從1往后編;
表類型的構造是如此的方便,以致于常常被人用來代替配置文件。是的,不用懷疑,它比ini文件要漂亮,并且強大的多。
F. Function
函數,在Lua中,函數的定義也很簡單。典型的定義如下:
function add(a,b) -- add 是函數名字,a和b是參數名字
return a+b -- return 用來返回函數的運行結果
end
請注意,return語言一定要寫在end之前。假如你非要在中間放上一句return,那么請寫成:do return end。
還記得前面說過,函數也是變量類型嗎?上面的函數定義,其實相當于:
add = function (a,b) return a+b end
當你重新給add賦值時,它就不再表示這個函數了。你甚至可以賦給add任意數據,包括nil (這樣,你就清除了add變量)。Function是不是很象C語言的函數指針呢?
和C語言一樣,Lua的函數可以接受可變參數個數,它同樣是用"…"來定義的,比如:
function sum (a,b,…)
如果想取得…所代表的參數,可以在函數中訪問arg局部變量(表類型)得到。
如 sum(1,2,3,4)
則,在函數中,a = 1, b = 2, arg = {3, 4}
更可貴的是,它可以同時返回多個結果,比如:
function s()
return 1,2,3,4
end
a,b,c,d = s() -- 此時,a = 1, b = 2, c = 3, d = 4
前面說過,表類型可以擁有任意類型的值,包括函數!因此,有一個很強大的特性是,擁有函數的表,哦,我想更恰當的應該說是對象吧。Lua可以使用面向對象編程了。不信?那我舉例如下:
t =
{
Age = 27
add = function(self, n) self.Age = self.Age+n end
}
print(t.Age) -- 27
t.add(t, 10)
print(t.Age) -- 37
不過,t.add(t,10) 這一句實在是有點土對吧?沒關系,在Lua中,你可以簡寫成:
t:add(10) -- 相當于 t.add(t,10)
G. Userdata 和 Thread
這兩個類型的話題,超出了本文的內容,就不打算細說了。
VI. 結束語
就這么結束了嗎?當然不是,接下來,需要用Lua解釋器,來幫助你理解和實踐了。這篇小文只是幫助你大體了解Lua的語法。如果你有編程基礎,相信會很快對Lua上手了。
就象C語言一樣,Lua提供了相當多的標準函數來增強語言的功能。使用這些標準函數,你可以很方便的操作各種數據類型,并處理輸入輸出。有關這方面的信息,你可以參考《Programming in Lua 》一書,你可以在網絡上直接觀看電子版,網址為:
http://www.lua.org/pil/index.html 當然,Lua的最強大的功能是能與宿主程序親蜜無間的合作,因此,下一篇文章,我會告訴大家,如何在你的程序中使用Lua語言作為腳本,使你的程序和Lua腳本進行交互。
作者: 沐楓 (第二人生成員)
版權所有轉載請注明原出處
主頁:第二人生
http://www.d2-life.com http://www.d2-life.com/LBS/blogview.asp?logID=41為什么要用Lua作腳本?
使用Lua作腳本,主要是因為它小巧玲瓏(體積小,運行快),而且它的語法又比較簡單明了。不過,使用LuaAPI將Lua引擎集成到程序中,確實有一些不方便——用落木隨風網友的話來說,就是"就象用匯編"。當然,現在你不用再這么辛苦了,因為你可以使用LuaWrapper For C++。使用這個工具,在C++中集成Lua腳本就是輕而易舉的事。你原有的C++函數和類,幾乎不需要任何改變,就可以與Lua腳本共享。
我們接下來,用實例來說明,如何用LuaWrapper來集成Lua腳本到你的程序中去。
1. 創建Lua引擎
LuaWrap lua; 或者 LuaWrap* lua = new LuaWrap;
創建一個LuaWrap對象,就是創建一個Lua腳本引擎。并且根據Lua的特性,你可以創建任意多個Lua引擎,甚至可以分布在不同的線程當中。
2. 裝載并執行腳本程序
你可以從緩沖區中裝載Lua腳本:
lua.LoadString(
"print('Hello World')"
);
當然,你也可以從文件中裝入,并執行Lua腳本:
Lua.LoadFile("./test.lua");
Lua的腳本,可以是源代碼,也可以經過編譯后的中間代碼。也許你對編譯后的中間代碼更感興趣——如果你不希望讓源代碼赤裸裸的袒露在大家的眼前。
3. 獲取和設置Lua變量
能夠獲取和設置腳本變量的內容,是一個最基本的功能。你可以使用GetGlobal和SetGlobal函數來做到這一點:
(1) 獲取變量:
int a = lua.GetGlobal<int>("a");
LuaTable table = lua.GetGlobal<LuaTable>("t");
這里,<> 里頭的類型,就是想要的變量的類型。
(2) 設置變量:
lua.SetGlobal("a", a);
lua.SetGlobal("t", table);
4. 調用Lua函數
使用Call函數,就可以很簡單的從你的程序中調用Lua函數:
lua.Call<void>("print", "Hello World");
int sum = lua.Call<int>("add", 2, 3);
這里,<> 里頭的類型是返回值的類型。
5. 如何讓Lua也能調用C++的函數
精采的地方來了。假如有下面這樣的一個函數:
int add(int a, int b)
{
return a + b;
}
如果想讓它能夠讓Lua使用,只需將它注冊到Lua引擎當中就可以了:
lua.RegisterFunc("add", int(int,int), add);
這樣,Lua中就可以用直接使用了:
(Lua腳本)sum = add(1, 3)
(*) RegisterFunc的功能,就是讓你把C++的函數注冊到Lua中,供Lua腳本使用。
第一個參數,是想要在Lua中用的函數名。
第二個參數,是C++中函數的原型; C++允許函數重載的,你可以使用函數原型,來選擇需要注冊到Lua引擎中的那個函數。
第三個參數,就是C++中函數的指針了。
6. 如何能讓C++的類在Lua中使用
我們先看看下面這個C++類:
class MyArray
{
std::vector<double> array;
public:
void setvalue(int index, double value);
double getvalue(int index);
int size();
const char* ToString();
};
你準備要讓Lua能夠自由訪問并操作這個類。很簡單,你只需增加幾個宏定義就可以了:
class MyArray
{
std::vector<double> array;
public:
void setvalue(int index, double value);
double getvalue(int index);
int size();
const char* ToString();
// 將一個 class 作為一個 Lua 對象是很容易的,只需要增加以下宏定義。
DEFINE_TYPENAME("My.array");
BEGIN_REGLUALIB("array")
LUALIB_ITEM_create("new", MyArray ) // 創建MyArray (注:由于發表的原因,create應為全部大寫)
LUALIB_ITEM_DESTROY("del", MyArray ) // 消除MyArray。
END_REGLUALIB()
BEGIN_REGLUALIB_MEMBER()
LUALIB_ITEM_FUNC("size", int (MyArray*), &MyArray::size)
LUALIB_ITEM_FUNC("__getindex", double(MyArray*, int), &MyArray::getvalue)
LUALIB_ITEM_FUNC("__newindex", void (MyArray*, int, double), &MyArray::setvalue)
LUALIB_ITEM_FUNC("__tostring", const char* (MyArray*), &MyArray::ToString)
LUALIB_ITEM_DESTROY("__gc", MyArray ) // 垃圾收集時消除對象用。
END_REGLUALIB_MEMBER()
};
只要有了這些宏定義,這個類就是可以在Lua中使用的類了,我們就可以在Lua中注冊這個類了:
lua.Register<MyArray>()
這樣注冊以后,我們在Lua中就可以使用這個類了:
a = array.new() -- 創建對象,相當于 a = new Myarray
a[1] = 10 -- 調用__newindex,也就是C++中的 a->setvalue(1, 10)
a[2] = 20 -- 調用__newindex,也就是C++中的 a->setvalue(2, 20)
print(
a, -- 調用 __tostring,也就是C++中的 a->ToString()
a:size(), -- 相當于C++中的 a->size()
a[1], -- 調用__getindex,也就是C++中的a->getvalue(1)
a[2]) --調用__getindex,也就是C++中的a->getvalue(2)
array.del(a) -- 清除對象,相當于 delete a
a = nil -- 清空 a,很象C++中的 a = NULL
當然,你也可以不用del這個對象,而是等待Lua幫你自動進行垃圾回收。在Lua進行垃圾回收時,它會自動調用這個對象的 __gc ,相當于 delete。
那么,在C++中要創建MyArray對象,并且傳遞給Lua全局變量怎么辦?就象前面講過的一樣,使用SetGlobal:
MyArray* a = new MyArray;
lua.SetGlobal("a", a);
要獲取該對象,同樣的,應該使用GetGlobal:
MyArray* a = lua.GetGlobal<MyArray>("a");
對于傳遞給Lua的對象,就讓Lua來管理該對象的生存周期好了。如果你非要刪除它的話,你可以使用DelGlobalObject:
lua.DelGlobalObject<MyArray>("a");
不過這么做的話,你應當明白你在做什么,因為在Lua的腳本中,可能已經在多處引用了這個對象了。刪除了其中一個,將導致其它引用對象失效,從而可能引致系統崩潰。
(1) DEFINE_TYPENAME("My.array");
定義類型的名稱。在Lua中,這個類型名稱是唯一用來識別C++類型的,你必須為不同的對象給予不同的名稱。
(2) BEGIN_REGLUALIB("array") … END_REGLUALIB()
你可以為一個對象定義一個程序庫,"array"就是程序庫的名字。在程序庫中定義的函數是全局函數,在Lua中,使用該函數,需要在函數前加上庫的名字,如:array.new()。通常,程序庫會包含創建對象的方法。如:
LUALIB_ITEM_create("new", MyArray ) // 創建MyArray (注:由于發表的原因,create應為全部大寫)
這樣子,你才能在Lua中創建MyArray:
a = array.new()
你也可以選擇增加一個刪除對象操作:
LUALIB_ITEM_DESTROY("del", MyArray ) // 刪除MyArray
這樣,你就可以直接刪除一個對象了:
array.del(a)
(3) BEGIN_REGLUALIB_MEMBER() …END_REGLUALIB_MEMBER()
在此處,你可以定義對象的成員函數,也可以重載對象的操作符——是的,就象C++的operator重載。例如:
LUALIB_ITEM_FUNC("__newindex", void (MyArray*, int, double), &MyArray::setvalue)
就是重載 operator[] 操作符。Lua中可重載的操作符還有許多,如:
__getindex:操作符[],支持讀取訪問,如 v = a[10]
__newindex:操作符[],支持賦值訪問,如 a[10] = 1.22
__tostring:將變量轉換成字串__add:等同于operator +
__add:操作符 +
__sub:操作符 –
__mul:操作符 ×
__div:操作符 ÷
__pow:操作符 ^ (乘方)
__unm:一元操作符 –
__concat:操作符 .. (字符串連接)
__eq:操作符 == (a ~= b等價于 not a == b)
__lt:操作符 < (a > b 等價于 b < a)
__le:操作符 <= (a >= b 等價于 b <= a,要注意的是,如果沒有定義"__le",則Lua將會嘗試將a<=b 轉換成 not (b < a) )
__gc:在垃圾回收時調用此函數,相當于C++的析構函數。強烈建議定義此操作符,以免造成內存泄漏等情況。比如:
LUALIB_ITEM_DESTROY("__gc", MyArray ) // 垃圾收集時消除對象用。
(注) 這里要說明一下,在lua中,訪問索引操作符是__index,不是__getindex,在luaWrapper庫中,為了方便使用,將其映射為__getindex,同時,對__index的定義將會被忽略。
就這么簡單。假如你已經有現成的類,而你沒有修改該類的權力,如何將其加入到Lua中呢?答案就是,繼承它,將把派生類加入到Lua中。
結束語
LuaWrapper 需要用到boost庫的支持:boost/type_traits.hpp, boost/function.hpp, boost/bind.hpp,它使用了C++的模板部份特化,因此,C++編譯器如果不支持此特性,將無法編譯。目前支持此特性的編譯器已經有很多。在VisualStudo產品系列中,只有VC7.1能支持此特性,因此,您如果正在使用VisualStudio,請確認你用的是VisualStudio2003。
如果你覺得 LuaWrapper For C++ 能夠幫助你,我會感覺很榮幸。我很愿意將這個程序庫分享給大家。順便一提的是,如果你在使用過程中發現BUG,或是有好的建議,希望您能與我聯系。你在使用過程中,請不要刪除文件中的署名信息;如果你修改了程序庫,請您在修改的文件中加入您的修改說明。當然,我會非常歡迎您能將修改后的程序回饋給我。我會繼續優化并完善它。
=============================================================
File: Click Here Download: LuaWrapper For C++
File: Click Here Download: LuaWrapper test program
一.Hello World
1.前言
偶最近在學習Lua, 所以寫出心得和大家共享, 爭取一天寫一篇, 嘿嘿.
才開始學所以內容很淺, 希望大家包涵.
Lua是一種完全免費的腳本語言, 可以和C/C++語言緊密結合,
它的官方網站在http://www.lua.org. 在網站上可以下載到lua的源碼, 沒有可
執行版本, 不過不用擔心, 因為lua源碼可以在任何一種C/C++的編譯器上編譯.
如果要學習Lua, 官方網站上的Reference是必備的,上面有每個命令的用法,非常詳細。
參考手冊 http://www.lua.org/manual/5.0/
作者寫的Programming in Lua http://www.lua.org/pil/
2.編譯 如果用的VC6, 可以下載所需的project文件,地址在
http://sourceforge.net/project/showfiles.php?group_id=32250&package_id=115604
VSNET2003可以下載這個sln文件http://home.comcast.net/~vertigrated/lua/vs7.zip
偶用的是cygwin和linux, 打入以下命令即可,
tar -zxvf lua-5.0.2.tar.gz
cd lua-5.0.2
sh ./configure
make
這樣就OK了。
為了以后使用方便,最好把bin目錄加入到path里面。
3."Hello, world!" 現在開始偶們的第一個小程序"Hello, world!"
把以下程序打入文件e01.lua
例1:e01.lua
-- Hello World in Lua
print("Hello World.")
Lua有兩種執行方式,一種是嵌入到C程序中執行,還有一種是直接從命令行方式下執行。
這里為了調試方便,采用第二種方式,執行命令 lua e01.lua
輸出結果應該是:
Hello World.
4.程序說明 第一行 -- Hello World in Lua
這句是注釋,其中--和C++中的//意思是一樣的
第二行 print("Hello World.")
調用lua內部命令print,輸出"Hello World."字符串到屏幕,Lua中的字符串全部是由"括起來的。
這個命令是一個函數的調用,print是lua的一個函數,而"Hello World."是print的參數。
5.試試看 在Lua中有不少字符串的處理操作,本次的課后試試看的內容就是,找出連接兩個字符串的操作,
并且print出來。
二.流程控制1. 函數的使用
以下程序演示了如何在Lua中使用函數, 及局部變量
例e02.lua
-- functions
function pythagorean(a, b)
local c2 = a^2 + b^2
return sqrt(c2)
end
print(pythagorean(3,4))
運行結果
5
程序說明
在Lua中函數的定義格式為:
function 函數名(參數)
...
end
與Pascal語言不同, end不需要與begin配對, 只需要在函數結束后打個end就可以了.
本例函數的作用是已知直角三角形直角邊, 求斜邊長度. 參數a,b分別表示直角邊長,
在函數內定義了local形變量用于存儲斜邊的平方. 與C語言相同, 定義在函數內的代
碼不會被直接執行, 只有主程序調用時才會被執行.
local表示定義一個局部變量, 如果不加local剛表示c2為一個全局變量, local的作用域
是在最里層的end和其配對的關鍵字之間, 如if ... end, while ... end等。全局變量的
作用域是整個程序。
2. 循環語句 例e03.lua
-- Loops
for i=1,5 do
print("i is now " .. i)
end
運行結果
i is now 1
i is now 2
i is now 3
i is now 4
i is now 5
程序說明
這里偶們用到了for語句
for 變量 = 參數1, 參數2, 參數3 do
循環體
end
變量將以參數3為步長, 由參數1變化到參數2
例如:
for i=1,f(x) do print(i) end
for i=10,1,-1 do print(i) end
這里print("i is now " .. i)中,偶們用到了..,這是用來連接兩個字符串的,
偶在(1)的試試看中提到的,不知道你們答對了沒有。
雖然這里i是一個整型量,Lua在處理的時候會自動轉成字符串型,不需偶們費心。
3. 條件分支語句 例e04.lua
-- Loops and conditionals
for i=1,5 do
print(“i is now “ .. i)
if i < 2 then
print(“small”)
elseif i < 4 then
print(“medium”)
else
print(“big”)
end
end
運行結果
i is now 1
small
i is now 2
medium
i is now 3
medium
i is now 4
big
i is now 5
big
程序說明
if else用法比較簡單, 類似于C語言, 不過此處需要注意的是整個if只需要一個end,
哪怕用了多個elseif, 也是一個end.
例如
if op == "+" then
r = a + b
elseif op == "-" then
r = a - b
elseif op == "*" then
r = a*b
elseif op == "/" then
r = a/b
else
error("invalid operation")
end
4.試試看 Lua中除了for循環以外, 還支持多種循環, 請用while...do和repeat...until改寫本文中的for程序
三.Lua數據結構 1.簡介 Lua語言只有一種基本數據結構, 那就是table, 所有其他數據結構如數組啦,
類啦, 都可以由table實現.
例e05.lua
-- Arrays
myData = {}
myData[0] = “foo”
myData[1] = 42
-- Hash tables
myData[“bar”] = “baz”
-- Iterate through the
-- structure
for key, value in myData do
print(key .. “=“ .. value)
end
輸出結果
0=foo
1=42
bar=baz
程序說明
首先定義了一個table myData={}, 然后用數字作為下標賦了兩個值給它. 這種
定義方法類似于C中的數組, 但與數組不同的是, 每個數組元素不需要為相同類型,
就像本例中一個為整型, 一個為字符串.
程序第二部分, 以字符串做為下標, 又向table內增加了一個元素. 這種table非常
像STL里面的map. table下標可以為Lua所支持的任意基本類型, 除了nil值以外.
Lua對Table占用內存的處理是自動的, 如下面這段代碼
a = {}
a["x"] = 10
b = a -- `b' refers to the same table as `a'
print(b["x"]) --> 10
b["x"] = 20
print(a["x"]) --> 20
a = nil -- now only `b' still refers to the table
b = nil -- now there are no references left to the table
b和a都指向相同的table, 只占用一塊內存, 當執行到a = nil時, b仍然指向table,
而當執行到b=nil時, 因為沒有指向table的變量了, 所以Lua會自動釋放table所占內存
3.Table的嵌套 Table的使用還可以嵌套,如下例
例e06.lua
-- Table ‘constructor’
myPolygon = {
color=“blue”,
thickness=2,
npoints=4;
{x=0, y=0},
{x=-10, y=0},
{x=-5, y=4},
{x=0, y=4}
}
-- Print the color
print(myPolygon[“color”])
-- Print it again using dot
-- notation
print(myPolygon.color)
-- The points are accessible
-- in myPolygon[1] to myPolygon[4]
-- Print the second point’s x
-- coordinate
print(myPolygon[2].x)
程序說明 首先建立一個table, 與上一例不同的是,在table的constructor里面有{x=0,y=0},
這是什么意思呢? 這其實就是一個小table, 定義在了大table之內, 小table的
table名省略了.
最后一行myPolygon[2].x,就是大table里面小table的訪問方式.
四.函數的調用 1.不定參數 例e07.lua
-- Functions can take a
-- variable number of
-- arguments.
function funky_print (...)
for i=1, arg.n do
print("FuNkY: " .. arg[i])
end
end
funky_print("one", "two")
運行結果
FuNkY: one
FuNkY: two
程序說明
* 如果以...為參數, 則表示參數的數量不定.
* 參數將會自動存儲到一個叫arg的table中.
* arg.n中存放參數的個數. arg[]加下標就可以遍歷所有的參數.
2.以table做為參數 例e08.lua
-- Functions with table
-- parameters
function print_contents(t)
for k,v in t do
print(k .. "=" .. v)
end
end
print_contents{x=10, y=20}
運行結果
x=10
y=20
程序說明
* print_contents{x=10, y=20}這句參數沒加圓括號, 因為以單個table為參數的時候, 不需要加圓括號
* for k,v in t do 這個語句是對table中的所有值遍歷, k中存放名稱, v中存放值
3.把Lua變成類似XML的數據描述語言 例e09.lua
function contact(t)
-- add the contact ‘t’, which is
-- stored as a table, to a database
end
contact {
name = "Game Developer",
email = "hack@ogdev.net",
url = "http://www.ogdev.net",
quote = [[
There are
10 types of people
who can understand binary.]]
}
contact {
-- some other contact
}
程序說明
* 把function和table結合, 可以使Lua成為一種類似XML的數據描述語言
* e09中contact{...}, 是一種函數的調用方法, 不要弄混了
* [[...]]是表示多行字符串的方法
* 當使用C API時此種方式的優勢更明顯, 其中contact{..}部分可以另外存成一配置文件
4.試試看 想想看哪些地方可以用到例e09中提到的配置方法呢?
五.Lua與C的交互 1.簡介 Lua與C/C++結合是很緊密的, Lua與C++交互是建立在Lua與C的基礎上的, 所
以偶先從Lua與C講起.
正如第一講所說, 運行Lua程序或者說調用Lua主要有兩種方式:
* 通過命令行執行"Lua"命令
* 通過Lua的C庫
雖然此前偶們一直用第一種方式, 但偶要告訴你, 通過Lua的C庫執行才是游戲中
常用的方式.
2.Lua的C庫 Lua的C庫可以做為Shared Library調用, 但一般開發游戲時會把Lua的所有源程序
都包含在內, 并不把Lua編譯成共享庫的形式. 因為Lua程序只有100多K, 而且幾乎
可以在任何編譯器下Clean Compile. 帶Lua源程序的另一個好處時, 可以隨時對Lua
本身進行擴充, 增加偶們所需的功能.
Lua的C庫提供一系列API:
* 管理全局變量
* 管理tables
* 調用函數
* 定義新函數, 這也可以完全由C實現
* 垃圾收集器Garbage collector, 雖然Lua可以自動進行, 但往往不是立即執行的,
所以對實時性要求比較高的程序, 會自己調用垃圾收集器
* 載入并執行Lua程序, 這也可以由Lua自身實現
* 任何Lua可以實現的功能, 都可以通過Lua的C API實現, 這對于優化程序的運行速度
有幫助. 經常調用的共用的Lua程序片斷可以轉成C程序, 以提高效率. 連Lua都是C寫的
還有什么C不能實現呢?
3.Lua與C集成的例子 例e10.c
/* A simple Lua interpreter. */
#include
#include
int main(int argc, char *argv[]) {
char line[BUFSIZ];
lua_State *L = lua_open(0);
while (fgets(line, sizeof(line), stdin) != 0)
lua_dostring(L, line);
lua_close(L);
return 0;
}
編譯
Linux/Cygwin
* 先編譯Lua, 并把頭文件放入include路徑
* gcc e10.c -llua -llualib -o e10
VC6/VC2003
* 先編譯Lua, 在Option中設置頭文件和庫文件路徑
* 新建工程,在工程配置中加入附加庫lua.lib和lualib.lib
* 編譯成exe
運行結果
本程序的功能是實現一個Lua解釋器, 輸入的每行字符都會被解釋成Lua并執行.
程序說明
* #include 包含lua頭文件, 然后才可以使用API
* lua_State *L = lua_open(0) 打開一個Lua執行器
* fgets(line, sizeof(line), stdin) 從標準輸入里讀入一行
* lua_dostring(L, line) 執行此行
* lua_close(L) 關閉Lua執行器
例e11.c
/* Another simple Lua interpreter. */
#include
#include
#include
int main(int argc, char *argv[]) {
char line[BUFSIZ];
lua_State *L = lua_open(0);
lua_baselibopen(L);
lua_iolibopen(L);
lua_strlibopen(L);
lua_mathlibopen(L);
while (fgets(line, sizeof(line), stdin) != 0)
lua_dostring(L, line);
lua_close(L);
return 0;
}
運行結果
本程序的功能是實現一個Lua解釋器, 輸入的每行字符都會被解釋成Lua并執行.
與上例不同的是, 本例調用了Lua的一些標準庫.
程序說明
* #include 包含Lua的標準庫
* 以下這幾行是用來讀入Lua的一些庫, 這樣偶們的Lua程序就可以有更多的功能.
lua_baselibopen(L);
lua_iolibopen(L);
lua_strlibopen(L);
lua_mathlibopen(L);
4.試試看
把上面兩個小例子在你熟悉的編譯器中編譯執行, 并試試能否與Lua源碼樹一起編譯
六.C/C++中用Lua函數
1.簡介
偶們這次主要說說怎么由Lua定義函數, 然后在C或者C++中調用. 這里偶們
暫不涉及C++的對象問題, 只討論調用函數的參數, 返回值和全局變量的使用.
2.程序
這里偶們在e12.lua里先定義一個簡單的add(), x,y為加法的兩個參數,
return 直接返回相加后的結果.
例e12.lua
-- add two numbers
function add ( x, y )
return x + y
end
在前一次里, 偶們說到 lua_dofile() 可以直接在C中執行lua文件. 因為偶們
這個程序里只定義了一個add()函數, 所以程序執行后并不直接結果, 效果相當
于在C中定義了一個函數一樣.
Lua的函數可以有多個參數, 也可以有多個返回值, 這都是由棧(stack)實現的.
需要調用一個函數時, 就把這個函數壓入棧, 然后順序壓入所有參數, 然后用
lua_call()調用這個函數. 函數返回后, 返回值也是存放在棧中. 這個過程和
匯編執行函數調用的過程是一樣的.
例e13.cpp 是一個調用上面的Lua函數的例子
#include
extern "C" { // 這是個C++程序, 所以要extern "C",
// 因為lua的頭文件都是C格式的
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
/* the Lua interpreter */
lua_State* L;
int luaadd ( int x, int y )
{
int sum;
/* the function name */
lua_getglobal(L, "add");
/* the first argument */
lua_pushnumber(L, x);
/* the second argument */
lua_pushnumber(L, y);
/* call the function with 2
arguments, return 1 result */
lua_call(L, 2, 1);
/* get the result */
sum = (int)lua_tonumber(L, -1);
lua_pop(L, 1);
return sum;
}
int main ( int argc, char *argv[] )
{
int sum;
/* initialize Lua */
L = lua_open();
/* load Lua base libraries */
lua_baselibopen(L);
/* load the script */
lua_dofile(L, "e12.lua");
/* call the add function */
sum = luaadd( 10, 15 );
/* print the result */
printf( "The sum is %d\n", sum );
/* cleanup Lua */
lua_close(L);
return 0;
}
程序說明:
main中過程偶們上次已經說過了, 所以這次只說說luaadd的過程
* 首先用lua_getglobal()把add函數壓棧
* 然后用lua_pushnumber()依次把x,y壓棧
* 然后調用lua_call(), 并且告訴程序偶們有兩個參數一個返回值
* 接著偶們從棧頂取回返回值, 用lua_tonumber()
* 最后偶們用lua_pop()把返回值清掉
運行結果:
The sum is 25
編譯方法
Linux下把程序存成e13.cpp
g++ e13.cpp -llua -llualib -o e13
./e13
VC下編譯方法
* 首先建立一個空的Win32 Console Application Project
* 把e13.cpp加入工程中
* 點project setting,然后設置link選項, 再加上lua.lib lualib.lib兩個額外的庫
* 最后編譯
建立好的project可以在這里下載
VC http://tonyandpaige.com/tutorials/luaadd.zip
Linux http://tonyandpaige.com/tutorials/luaadd.tar.gz
3.全局變量
上面偶們用到了lua_getglobal()但并沒有詳細講, 這里偶們再舉兩個小例子來說下全局變量
lua_getglobal()的作用就是把lua中全局變量的值壓入棧
lua_getglobal(L, "z");
z = (int)lua_tonumber(L, 1);
lua_pop(L, 1);
假設Lua程序中定義了一個全局變量z, 這段小程序就是把z的值取出放入C的變量z中.
另外Lua中還有一個對應的函數lua_setglobal(), 作用是用棧頂的值填充指定的全局變量
lua_pushnumber(L, 10);
lua_setglobal(L, "z");
例如這段小程序就是把lua中的全局變量z設為10, 如果lua中未定義z的話, 就會自動創建一個
全局變量z并設為10.
4.試試看
自己寫個函數用C/C++來調用下試試
七.調用C/C++函數
1.前言
上次偶說到從C/C++中調用Lua的函數, 然后就有朋友問從Lua中如何調用C/C++的
函數, 所以偶們這次就來說說這個問題. 首先偶們會在C++中建立一個函數, 然后
告知Lua有這個函數, 最后再執行它. 另外, 由于函數不是在Lua中定義的, 所以
無法確定函數的正確性, 可能在調用過程中會出錯, 因此偶們還會說說Lua出錯處
理的問題.
2.Lua中調用C函數
在lua中是以函數指針的形式調用函數, 并且所有的函數指針都必須滿足如下此種
類型:
typedef int (*lua_CFunction) (lua_State *L);
也就是說, 偶們在C++中定義函數時必須以lua_State為參數, 以int為返回值才能
被Lua所調用. 但是不要忘記了, 偶們的lua_State是支持棧的, 所以通過棧可以
傳遞無窮個參數, 大小只受內存大小限制. 而返回的int值也只是指返回值的個數
真正的返回值都存儲在lua_State的棧中. 偶們通常的做法是做一個wrapper, 把
所有需要調用的函數都wrap一下, 這樣就可以調用任意的函數了.
下面這個例子是一個C++的average()函數, 它將展示如何用多個參數并返回多個值
例e14.cpp
#include
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
/* the Lua interpreter */
lua_State* L;
static int average(lua_State *L)
{
/* get number of arguments */
int n = lua_gettop(L);
double sum = 0;
int i;
/* loop through each argument */
for (i = 1; i <= n; i++)
{
/* total the arguments */
sum += lua_tonumber(L, i);
}
/* push the average */
lua_pushnumber(L, sum / n);
/* push the sum */
lua_pushnumber(L, sum);
/* return the number of results */
return 2;
}
int main ( int argc, char *argv[] )
{
/* initialize Lua */
L = lua_open();
/* load Lua base libraries */
lua_baselibopen(L);
/* register our function */
lua_register(L, "average", average);
/* run the script */
lua_dofile(L, "e15.lua");
/* cleanup Lua */
lua_close(L);
return 0;
}
例e15.lua
-- call a C++ function
avg, sum = average(10, 20, 30, 40, 50)
print("The average is ", avg)
print("The sum is ", sum)
程序說明:
* lua_gettop()的作用是返回棧頂元素的序號. 由于Lua的棧是從1開始編號的,
所以棧頂元素的序號也相當于棧中的元素個數. 在這里, 棧中元素的個數就
是傳入的參數個數.
* for循環計算所有傳入參數的總和. 這里用到了數值轉換lua_tonumber().
* 然后偶們用lua_pushnumber()把平均值和總和push到棧中.
* 最后, 偶們返回2, 表示有兩個返回值.
* 偶們雖然在C++中定義了average()函數, 但偶們的Lua程序并不知道, 所以需
要在main函數中加入
/* register our function */
lua_register(L, "average", average);
這兩行的作用就是告訴e15.lua有average()這樣一個函數.
* 這個程序可以存成cpp也可以存成c, 如果以.c為擴展名就不需要加extern "C"
編譯的方法偶們上次說過了, 方法相同.
e15.lua執行的方法只能用上例中的C++中執行, 而不能用命令行方式執行.
3.錯誤處理
在上例中, 偶們沒有對傳入的參數是否為數字進行檢測, 這樣做不好. 所以這里偶
們再加上錯誤處理的片斷.
把這段加在for循環之內:
if (!lua_isnumber(L, i)) {
lua_pushstring(L, "Incorrect argument to 'average'");
lua_error(L);
}
這段的作用就是檢測傳入的是否為數字.
加上這段之后, 偶們debug的時候就會簡單許多. 對于結合兩種語言的編程, 它們之
間傳遞數據的正確性檢測是非常重要的.
這里有別人寫好的例子:
VC的 http://tonyandpaige.com/tutorials/luaavg.zip
Linux的 http://tonyandpaige.com/tutorials/luaavg.tar.gz
Lua 的 5.1 版本已經正式發布。現在,我們應該把全部討論放在這個版本上。
應該盡量使用 local 變量而非 global 變量。這是
Lua 初學者最容易犯的錯誤。global 變量實際上是放在一張全局的 table 里的。global 變量實際上是利用一個 string (變量名作 key) 去訪問這個 table 。雖然
Lua5 的 table 效率很高 ,但是相對于 local 變量,依然有很大的效率損失。local 變量是直接通過
Lua 的堆棧訪問的。有些 global 變量的訪問是不經意的,比如我們有雙重循環操作一個迭代的 table:
for k1,v1 inpairs(tbl)dofor k2,v2 inpairs(v1)do
...
end
end
這里,pairs 其實是一個全局變量應用的函數。如果我們這樣做:
dolocalpairs=pairs
for k1,v1 inpairs(tbl)dofor k2,v2 inpairs(v1)do
...
endend
end
效率會稍微提高一些。如果是單層循環,這樣做就沒有意義。因為 for ... in 循環中的 pairs 這個函數只會被調用一次,而不是每次循環都去調。我們的原則其實是,被多次讀取的 global 變量,都應該提取出來放到 local 變量中。
警惕臨時變量 字符串的連接操作,會產生新的對象。這是由 lua 本身的 string 管理機制導致的。lua 在 VM 內對相同的 string 永遠只保留一份唯一 copy ,這樣,所有字符串比較就可以簡化為地址比較。這也是 lua 的 table 工作很快的原因之一。這種 string 管理的策略,跟 java 等一樣,所以跟 java 一樣,應該盡量避免在循環內不斷的連接字符串,比如 a = a..x 這樣。每次運行,都很可能會生成一份新的 copy 。
同樣,記住,每次構造一份 table 都會多一份 table 的 copy 。比如在 lua 里,把平面坐標封裝成 { x, y } 用于參數傳遞,就需要考慮這個問題。每次你想構造一個坐標對象傳遞給一個函數,{ 10,20 } 這樣明確的寫出,都會構造一個新的 table 出來。要么,我們想辦法考慮 table 的重用;要么,干脆用 x,y 兩個參數傳遞坐標。
同樣需要注意的是以 function foo (...) 這種方式定義函數, ... 這種不定參數,每次調用的時候都會被定義出一個 table 存放不定數量的參數。
這些臨時構造的對象往往要到 gc 的時候才被回收,過于頻繁的 gc 有時候正是效率瓶頸。
使用 closure 代替 table 上面提到封裝坐標的問題。誠然,我們可以用 { x=1,y=2 } 這樣封裝一個坐標。不過還有一個方法可供選擇。它稍微輕量一點。
function point (x,y)returnfunction()return x,y end
end
-- 使用范例
p=point(1,2)print(p())-- 輸出 1 2
如果你愿意,還可以做的復雜一點:
function point (x,y)returnfunction(idx)if idx=="x"thenreturn x
elseif idx=="y"thenreturn y
elsereturn x,y endend
end
-- 使用范例
p=point(1,2)print(p("x"))-- 1print(p("y"))-- 2
x,y 實際被存放在 closure 里,每次調用 function point 都有一份獨立的 closure。當然,function 的 code 只有一份。
設法減少從 C 向 Lua 傳遞字符串 字符串常量在 Lua VM 內部工作的非常快,但是一個從 C 向 lua vm 通過 lua_pushstring 之類的 api 傳遞進 VM 時,就需要掂量一下了。這至少包含一個再 hash 和匹配的過程。
我的 Blog 上的一篇文章討論了這個問題。
lua 中的繼承 lua 中實現 OO ,虛表往往設置一個 metatable 并設置 __index ,而繼承則用 metatable 的 __index 把虛表串起來。當類繼承層次過多的時候,效率比較低,那么就可以用下面這個技巧。
function inherit(sub,super)setmetatable(sub,
{ __index=function(t,k)local ret=super[k]
sub[k]=ret
return ret
end})end
利用邏輯運算的短路效應 lua 編程中,and or 跟 C 一樣是有短路效應的,不過他們的返回值并非 bool 類型,而是表達式中的左值或者右值。我們常常利用這個特性來簡化代碼。
function foo(arg)
arg=arg or"default"
...
end
利用 or 運算賦缺省值是最常用的技巧。上例中,如果 arg 為 nil ,arg 就會被賦值為 "default" 。但是這個技巧有個缺陷,當缺省值是 true 的時候會有點問題。
a=a ortrue-- 錯誤的寫法,當 a 明確寫為 false 的時候,也會被改變成 true 。
a= a ~= false-- 正確的寫法,當 a 為 nil 的時候,被賦值為 true ;而 false 則不變。
另外,巧妙使用 and or 還可以實現類似 C 語言中的 ?: 三元操作:
functionmax(a,b)return a>b and a or b
end
上面這個函數可以返回 a 和 b 中較大的一個,其邏輯類似 C 語言中的 return (a>b) ? a : b ;
我這個人記性不好,學過的東西老是愛忘,學得越多忘得越快,腦子和我可憐的硬盤一樣容量比較小,所以我發現我不得不把有些東西記錄下來。其實學一樣東西關鍵在于多學多用,有道是書讀百遍其意自現,對于我這種比較笨又沒天賦的人來說可謂金玉良言了。
以上算前言吧,下邊才是正文。
Ogre這個引擎的效率不知道實際應用起來如何,但是聽說結構倒是比較好的。選擇它來學習主要是因為它開源,而且是C++和Dx寫的,關鍵還有資料比較多,國內研究的也比較多,也有一些教程,不過Ogre不斷推出新版本,許多教程都有點過期了。要了解最新的使用方法還得看官方的教程。我也是直接看官方的教程,但是英文一般,每次打開大片英文頁面看著的確比較迷糊,所以我打算把里面一些重要的關鍵部分節選出來以備參考,有時候可以快速的重溫,比如這篇要介紹的如何配置Ogre,需要記嗎?程序員記不了那么多啦,用的時候再查。當然Ogre也在持續更新,如果我個人還在持續學習使用Ogre,那么我也會持續更新這些教程的,如果你是Ogre的使用者記得來我的Blog:http://www.shnenglu.com/singohgod 看看吧,希望能對大家有點幫助。
首先安裝SDK,可以編譯里面帶的示例看看一些效果展示。編譯源碼就得下載源碼吧,記得還要下一個Dependencies,解壓到源碼目錄就可以了,編譯應該能通過的,我這里沒有遇到問題。
不要被繁多的目錄和文件嚇著了,其實運行Ogre程序只需要下列庫和文件:
OGRE Libraries & Files
- OGRE libraries (OgreMain[_d].dll, OgrePlatform[_d].dll or libOgreMain.so, libOgrePlatform.so for linux).
- plugins.cfg - Text file specifying the rendering libraries available to Ogre (ie DX9, OpenGL).
- All the plugin libraries listed in plugins.cfg (you can remove items from plugins.cfg if you don't wish to use them).
- resources.cfg - If using the ExampleApplication, a text file specifing paths to materials, textures, models, etc.
- OgreCore.zip - Ensure resources.cfg has the proper path to this file if you plan to use the OGRE debug panel or profiler.
- Other Resources used in your program (*.zip; *.png; *.particle; *.mesh; ...).
還需要其他的第三方庫:
These are required:
- Zlib: zlib1.dll; libz.so (debian: zlib1g, zlib1g-dev)
- DevIL: devil.dll, ilu.dll, ilut.dll; libIL.so, libILU.so (debian: libdevil1, libdevil-dev)
These are optional:
- CEGUI: OgreGUIRenderer[_d].dll, CEGUIBase[_d].dll, CEGUITaharezLook[_d].dll, CEGUIWindowsLook[_d].dll, xerces-c_2_5_0.dll
- CEGUI: libCEGUIBase.so, libCEGUIOgreRenderer.so, libxerces-c.so (debian: libcegui-mk2-0, libcegui-mk2-dev, libxerces26, libxerces26-dev)
- Cg: cg.dll; libCg.so (debian: nvidia-cg-toolkit)
- OpenEXR: openexr.dll??; (debian: libopenexr-dev libopenexr2 )
- ReferenceApp: ReferenceAppLayer.dll
不同的編譯器還需要有:
Extras for Microsoft Visual C++ 6 (SP3+)
- stlport_vc6[_stldebug]46.dll
- msvcp60[D].dll
- msvcrt[D].dll
- Extras for Microsoft Visual C++.Net 2002
- stlport_vc7[_stldebug]46.dll
- msvcp70[d].dll
- msvcr70[d].dll
- Extras for Microsoft Visual C++.Net 2003
- msvcp71[d].dll
- msvcr71[d].dll
- Extras for Mingw + STLPort
- libstlport[stlg].5.0.dll
- mingwm10.dll
設置環境變量:
If you downloaded and installed the precompiled OGRE SDK, you should already have an environment variable called 'OGRE_HOME' registered already, pointing at the folder where you installed. If it isn't there you probably installed under a different user, so define OGRE_HOME manually
If you downloaded the source distribution, you should register a new environment variable OGRE_SRC pointing at the 'ogrenew' folder from the OGRE source
Ogre源碼項目的目錄結構:
work_dir
include
*.h
src
*.cpp
scripts
*.vcproj
新建項目也依據這個結構,你的項目應該有這些文件夾:'bin', 'include', 'media', 'testsolution', 'scripts', and 'src'
修改新項目的屬性:
Debugging : Working Directory = ..\bin\Debug
C/C++ : Preprocessor : Preprocessor Definitions += _STLP_DEBUG (only in Debug mode, not needed for .Net 2003 and 2005)
C/C++ : Code Generation : Use runtime library = Multithreaded Debug DLL (Multithreaded DLL in Release)
Linker : General : Output File = ..\bin\Debug\[appname].exe
Linker : Input : Additional Dependencies += OgreMain_d.lib (OgreMain.lib in Release)
如果你是安裝SDK:
C/C++ : General : Additional Include Directories = ..\include;$(OGRE_HOME)\include;$(OGRE_HOME)\samples\include
Linker : General : Additional Library Directories = $(OGRE_HOME)\lib
如果你是編譯源碼:
C/C++ : General : Additional Include Directories = ..\include;$(OGRE_SRC)\OgreMain\include;$(OGRE_SRC)\Samples\Common\Include
Linker : General : Additional Library Directories = $(OGRE_SRC)\OgreMain\Lib\Debug
這些設置好以后你就可以新建一個SampleApp.cpp文件,然后拷貝如下代碼:
#include "ExampleApplication.h"

// Declare a subclass of the ExampleFrameListener class
class MyListener : public ExampleFrameListener


{
public:
MyListener(RenderWindow* win, Camera* cam) : ExampleFrameListener(win, cam)

{
}

bool frameStarted(const FrameEvent& evt)

{
return ExampleFrameListener::frameStarted(evt);
}

bool frameEnded(const FrameEvent& evt)

{
return ExampleFrameListener::frameEnded(evt);
}
};

// Declare a subclass of the ExampleApplication class
class SampleApp : public ExampleApplication


{
public:
SampleApp()

{
}

protected:
// Define what is in the scene
void createScene(void)

{
// put your scene creation in here
}
// Create new frame listener
void createFrameListener(void)

{
mFrameListener = new MyListener(mWindow, mCamera);
mRoot->addFrameListener(mFrameListener);
}
};

#ifdef __cplusplus

extern "C"
{
#endif

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT)
#else
int main(int argc, char **argv)
#endif


{
// Instantiate our subclass
SampleApp myApp;


try
{
// ExampleApplication provides a go method, which starts the rendering.
myApp.go();
}

catch (Ogre::Exception& e)
{
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
MessageBoxA(NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
std::cerr << "Exception:\n";
std::cerr << e.getFullDescription().c_str() << "\n";
#endif
return 1;
}

return 0;
}

#ifdef __cplusplus
}
#endif

未完!
3D圖形技術常用技術一覽
一、場景管理相關的技術(scene manager th):
八叉樹(octree) 、四叉樹(quadtree)、二叉樹(biniary space tree)、多叉樹(n - tree)、入口技術(portal)、擴展入口(anti-portal)
二、通用內核渲染管理技術(render manager)
隊列(queue)、優先隊列(deque)、鏈表(list)
三、地形管理和繪制技術(terrain manager and render engine)
四叉樹(quadtree,和scenemanager重合)、單位地形塊管理(terrainChunk)、分塊地形(mapTile)、
二元三角樹(rometree)
四、通用不可見面去除技術
背面剔除(back cull)、視口截頭體剪裁(frustum)、遮擋面剔除(HBR)
五、通用動畫技術
關鍵幀動畫(frame animate)、骨骼蒙皮動畫(skeleton and skin mesh animate)、頂點動畫(vertex animate)、紋理動畫(textue animate)
六、通用材質紋理技術:
單紋理(single texture)、多重紋理(multpile texture)、透明度紋理(alpha texture)、陰影貼圖(shadow map)、光照貼圖(light map)、法線貼圖(normal texture)、高動態范圍光照圖(high dynamic range texture,用浮點紋理來模擬廣泛的光照范圍)、頂點置換圖(displacement texture,利用法線圖、高度圖和相對偏離圖進行物體模型的簡化)、高度圖(high texture)
七、光照陰影:
光線跟蹤(ray trace)、光照圖(light map)、陰影圖(shadow map)、動態光照(dynamic light)、體積陰影(shadow volumn)、模板陰影(stencil shadow)、頂點光照(vertex light)、像素光照(pixel light)、HDR、PRT
八、雜項:
粒子動畫系統,帶子動畫系統,3ds max\maya\lightwave\vue infinite插件
九、圖形處理器技術(GPU programming)
vs、ps、HLSL、CG
C++資源之不完全導引(完整版) |
|
C++資源之不完全導引(完整版)
來源:www.csdn.net
撰文:曾毅、陶文
聲明:本文2004年5月首發于《CSDN開發高手》,版權歸該雜志與《程序員》雜志社 所有。
------------------------------------------------------------------------ --------
|
1,前言
無數次聽到“我要開始學習C++!”的吶喊,無數次聽到“C++太復雜了,我真的
學不會”的無奈。Stan Lippman先生曾在《C++ Primer》一書中指出“C++是最為難
學的高級程序設計語言之一”,人們常將“之一”去掉以表達自己對C++的敬畏。誠
然,C++程序設計語言對于學習者的確有很多難以逾越的鴻溝,體系結構的龐大,應
接不暇并不斷擴充的特性……除此之外,參考資料之多與冗雜使它的學習者望而卻
步,欲求深入者苦不堪言。希望這一份不完全導引能夠成為您C++學習之路上的引路
燈。
撰寫本文的初衷并不打算帶領大家體驗古老的C++歷史,如果你想了解C++的歷
史與其前期發展中諸多技術的演變,你應當去參考Bjarne的《The Design and Evo
lution of C++》。當然也不打算給大家一個無所不包的寶典(并非不想:其一是因
水平有限,其二無奈C++之博大精深),所給出的僅僅是一些我們認為對于想學習C
++的廣大讀者來說最重要并且觸手可及的開發與學習資源。
本文介紹并分析了一些編譯器,開發環境,庫,少量的書籍以及參考網站,并
且盡可能嘗試著給出一個利用這些資源的導引,望對如同我們一樣的初學者能夠有
所裨益。
------------------------------------------------------------------------
--------
2,編譯器
在C++之外的任何語言中,編譯器都從來沒有受到過如此之重視。因為C++是一
門相當復雜的語言,所以編譯器也難于構建。直到最近我們才開始能夠使用上完全
符合C++標準的編譯器(哦,你可能會責怪那些編譯器廠商不能盡早的提供符合標準
的編譯器,這只能怪他們各自維系著自身的一套別人不愿接受的標準)。什么?你
說這無關緊要?哦,不,你所需要的是和標準化C++高度兼容的編譯環境。長遠來看
,只有這樣的編譯器對C++開發人員來說才是最有意義的工具,尤其是對于程序設計
語言的學習者。一至性讓代碼具備可移植性,并讓一門語言及其庫的應用更為廣泛
。嗯,是的,我們這里只打算介紹一些公認的優秀編譯器。
2.1 Borland C++
這個是Borland C++ Builder和Borland C++ Builder X這兩種開發環境的后臺
編譯器。(哦,我之所以將之分為兩種開發環境你應當能明白為什么,正如Delphi
7到Delphi8的轉變,是革命性的兩代。)Borland C++由老牌開發工具廠商Borland
傾力打造。該公司的編譯器素以速度快,空間效率高著稱,Borland C++ 系列編譯
器秉承了這個傳統,屬于非常優質的編譯器。標準化方面早在5.5版本的編譯器中對
標準化C++的兼容就達到了92.73%。目前最新版本是Borland C++ Builder X中的6.
0版本,官方稱100%符合ANSI/ISO的C++標準以及C99標準。嗯…這正是我前面所指的
“完全符合C++標準的編譯器”。
2.2 Visual C++
這個正是我們熟知的Visual Studio 和 Visual Studio.net 2002, 2003以及2
005 Whidbey中帶的C++編譯器。由Microsoft公司研制。在Visual Studio 6.0中,
因為編譯器有太多地方不能與后來出現的C++標準相吻合而飽受批評(想想你在使用
STL的時候編譯時報出的那些令人厭惡的error和warning吧)。VC++6.0對標準化C+
+的兼容只有83.43%。但是隨著C++編譯器設計大師Stanley Lippman以及諸多C++社
群達人的加盟,在Visual Studio.NET 2003中,Visual C++編譯器已經成為一個非
常成熟可靠的C++編譯器了。Dr.Dobb's Journal的評測顯示Visual C++7.1對標準C
++的兼容性高達98.22%,一度成為CBX之前兼容性最好的編譯器。結合強大的Visua
l Studio.NET開發環境,是一個非常不錯的選擇。至于Whidbey時代的Visual C++,
似乎微軟所最關注的是C++/CLI……我們不想評論微軟下一代的C++編譯器對標準化
兼容如何,但他確實越來越適合.NET (其實你和我的感覺可能是一樣的,微軟不應
當把標準C++這塊肥肉丟給Borland,然而微軟可能并不這樣認為)。
2.3 GNU C++
著名的開源C++編譯器。是類Unix操作系統下編寫C++程序的首選。特點是有非
常好的移植性,你可以在非常廣泛的平臺上使用它,同時也是編寫跨平臺,嵌入式
程序很好的選擇。另外在符合標準這個方面一直都非常好,GCC3.3大概能夠達到96
.15%。但是由于其跨平臺的特性,在代碼尺寸速度等優化上略微差一點。
基于GNU C++的編譯器有很多,比如:
(1) Mingw
http://www.mingw.org/
GCC的一個Windows的移植版本(Dev-C++的后臺)
(2) Cygwin
http://sources.redhat.com/cygwin/
GCC的另外一個Windows移植版本是Cygwin的一部分,Cygwin是Windows下的一個
Unix仿真環境。嚴格的說是模擬GNU的環境,這也就是"Gnu's Not Unix"要表達的意
思,噢,扯遠了,這并不是我們在這里關心的實質內容。
(3) Djgpp
http://www.delorie.com/djgpp/
這是GCC的DOS移植版本。
(4) RSXNT
http://www.mathematik.uni-bielefeld.de/~rainer/
這是GCC的DOS和Windows移植版本。
(5) Intel C++
著名CPU制造廠商Intel出品的編譯器,Special Design for Intel x86!對于
Intel x86結構的CPU經過特別的優化。在有些應用情況下,特別是數值計算等高性
能應用,僅僅采用Intel的編譯器編譯就能大幅度的提高性能。
(6) Digital Mars C++
網絡上提供免費下載,Zortech/Symantec C++的繼承者,其前身在當年慘烈的
C++四國戰中也是主角之一。
------------------------------------------------------------------------
--------
3,開發環境
開發環境對于程序員的作用不言而喻。選擇自己朝夕相處的環境也不是容易的
事情,特別是在IDE如此豐富的情況下。下面就是我們推薦的一些常見的C++開發環
境,并沒有包括一些小型的,罕見的IDE。其中任何一款都是功能豐富,可以用作日
常開發使用的。對于不同層面的開發者,請參見內文關于適用對象的描述。
3.1 Visual Studio 6.0
這個雖然是Microsoft公司的老版本的開發環境,但是鑒于其后繼版本Visual
Studio.NET的龐大身軀,以及初學者并不那么高的功能要求,所以推薦這個開發環
境給C++的初學者,供其學習C++的最基本的部分,比如C的那部分子集,當然你別指
望他能夠支持最新的C99標準。在日常的開發中,仍然有很多公司使用這個經典穩定
的環境,比如筆者就看曾親見有些公司將其編譯器替換為GCC做手機開發之用。
3.2 Visual Studio.NET 2003
作為Microsoft公司官方正式發布的最新版本開發環境,其中有太多激動人心的
功能。結合其最新的C++編譯器。對于機器配置比較好的開發人員來說,使用這個開
發環境將能滿足其大部分的要求。這里不打算單獨說Visual Studio Whidbey,雖然
Visual Studio .NET 2005 - Whidbey社區預覽版已經推出,但暫不是很穩定,讀者
可以親身去體驗。
3.3 Borland C++ Builder 6
這個并不是Borland的C++開發環境的最新版本。選擇它的原因是它不是用Java
寫的IDE,速度比較快。它有一個很完善的GUI窗體設計器,和Delphi共用一個VCL。
由于這些特點,比較適合初學者上手。但是由于其GUI的中心位置,可能不利于對于
C++語言的學習。而且其為了支持VCL這個Object Pascal寫的庫也對C++進行了一些
私有的擴充。使得人們有一個不得不接受的事實:“Borland C++ Builder 6的高手
幾乎都是Delphi高手”。
3.4 Borland C++ Builder X
正如前文所述,雖然版本號上和前面那個IDE非常相象,但是其實它們是完全不
同的兩個集成開發環境。C++Builder更多的是一個和Delphi同步的C++版本的開發環
境,C++BuilderX則是完全從C++的角度思考得出的一個功能豐富的IDE。其最大的特
點是跨平臺,跨編譯器,多種Framework的集成,并且有一個WxWindows為基礎的GU
I設計器。尤其是采用了純C++來重寫了整個Framework,摒棄了以前令人無奈的版本
。對于C++的開發來說,從編譯器,到庫,到功能集成都是非常理想的。可以預見,
Borland C++ Builder X 2.0很值得C++愛好者期待。唯一令人難堪之處是作為一個
C++的開發工具,其IDE是用Java寫的,在配置不夠理想的機器上請慎重考慮再安裝
。
3.5 Emacs + GCC
前面講的大部分是Windows環境下的集成開發環境。Linux上的開發者更傾向于
使用Emacs來編輯C++的文件,用Makefile來命令GCC做編譯。雖然看上去比較松散,
但是這些東西綜合起來還是一個開0發環境。如果你能夠嫻熟的使用這樣的環境寫程
序,你的水平應該足夠指導我們來寫這篇陋文了。
3.6 Dev C++
GCC是一個很好的編譯器。在Windows上的C++編譯器一直和標準有著一段距離的
時候,GCC就是一個讓Windows下開發者流口水的編譯器。Dev-C++就是能夠讓GCC跑
在Windows下的工具,作為集成開發環境,還提供了同專業IDE相媲美的語法高亮,
代碼提示,調試等功能。由于使用Delphi開發,占用內存少,速度很快,比較適合
輕量級的學習和使用。
3.7 Eclipse + CDT
Eclipse可是近來大名鼎鼎的開發工具。最新一期的Jolt大獎就頒給了這個杰出
的神物。說其神奇是因為,它本身是用Java寫的,但是擁有比一般Java寫的程序快
得多的速度。而且因為其基于插件組裝一切的原則,使得能夠有CDT這樣的插件把E
clipse變成一個C/C++的開發環境。如果你一直用Eclipse寫Java的程序,不妨用它
體驗一下C++開發的樂趣。
------------------------------------------------------------------------
--------
4,工具
C++的輔助工具繁多,我們分門別類的為大家作介紹:
4.1 文檔類
(1) Doxygen
參考站點:http://www.doxygen.org
Doxygen是一種適合C風格語言(如C++、C、IDL、Java甚至包括C#和PHP)的、
開放源碼的、基于命令行的文檔產生器。
(2) C++2HTML
參考站點:http://www.bedaux.net/cpp2html/
把C++代碼變成語法高亮的HTML
(3) CodeColorizer
參考站點:http://www.chami.com/colorizer/
它能把好幾種語言的源代碼著色為HTML
(4) Doc-O-Matic
參考站點:http://www.doc-o-matic.com/
Doc-O_Matic為你的C/C++,C++.net,Delphi/Pascal, VB.NET,C#和Java程序
或者組件產生準確的文檔。Doc-O-Matic使用源代碼中的符號和注釋以及外部的文檔
文件創建與流行的文檔樣式一致的文檔。
(5) DocVizor
參考站點:http://www.ucancode.net/Products/DocBuilder/Features.htm
DocVizor滿足了面向對象軟件開發者的基本要求——它讓我們能夠看到C++工程
中的類層次結構。DocVizor快速地產生完整可供打印的類層次結構圖,包括從第三
方庫中來的那些類,除此之外DocVizor還能從類信息中產生HTML文件。
(6) SourcePublisher C++
參考站點:http://www.scitools.com/sourcepublisher_c.html
給源代碼產生提供快速直觀的HTML報表,包括代碼,類層次結構,調用和被調
用樹,包含和被包含樹。支持多種操作系統。
(7) Understand
參考站點:http://www.scitools.com/ucpp.html
分析任何規模的C或者C++工程,幫助我們更好的理解以及編寫文檔。
4.2 代碼類
(1) CC-Rider
參考站點:http://www.cc-rider.com
CC-Rider是用于C/C++程序強大的代碼可視化工具,通過交互式瀏覽、編輯及自
動文件來促進程序的維持和發展。
(2) CodeInspect
參考站點:http://www.yokasoft.com/
一種新的C/C++代碼分析工具。它檢查我們的源代碼找出非標準的,可能的,以
及普通的錯誤代碼。
(3) CodeWizard
參考站點:http://www.parasoft.com
先進的C/C++源代碼分析工具,使用超過500個編碼規范自動化地標明危險的,
但是編譯器不能檢查到的代碼結構。
(4) C++ Validation Test Suites
參考站點:http://www.plumhall.com/suites.html
一組用于測試編譯器和庫對于標準吻合程度的代碼庫。
(5) CppRefactory
參考站點:http://cpptool.sourceforge.net/
CPPRefactory是一個使得開發者能夠重構他們的C++代碼的程序。目的是使得C
++代碼的重構能夠盡可能的有效率和簡單。
(6) Lzz
參考站點:http://www.lazycplusplus.com/
Lzz是一個自動化許多C++編程中的體力活的工具。它能夠節省我們許多事件并
且使得編碼更加有樂趣。給出一系列的聲明,Lzz會給我們創建頭文件和源文件。
(7) QA C++ Generation 2000
參考站點:http://www.programmingresearch.com/solutions/qacpp.htm
它關注面向對象的C++源代碼,對有關于設計,效率,可靠性,可維護性的部分
提出警告信息。
(8) s-mail project - Java to C++DOL
參考站點:http://sadlocha.strefa.pl/s-mail/ja2dol.html
把Java源代碼翻譯為相應的C++源代碼的命令行工具。
(9) SNIP from Cleanscape Software International
參考站點:http://www.cleanscape.net/stdprod/snip/index.html
一個填平編碼和設計之間溝壑的易于使用的C++開發工具,節省大量編輯和調試
的事件,它還使得開發者能夠指定設計模式作為對象模型,自動從對象模型中產生
C++的類。
(10) SourceStyler C++
參考站點:http://www.ochresoftware.com/
對C/C++源代碼提供完整的格式化和排版控制的工具。提供多于75個的格式化選
項以及完全支持ANSI C++。
4.3 編譯類
(1) Compilercache
參考站點:http://www.erikyyy.de/compilercache/
Compilercache是一個對你的C和C++編譯器的封裝腳本。每次我們進行編譯,封
裝腳本,把編譯的結果放入緩存,一旦編譯相同的東西,結果將從緩存中取出而不
是再次編譯。
(2) Ccache
參考站點:http://ccache.samba.org/
Ccache是一個編譯器緩存。它使用起來就像C/C++編譯器的緩存預處理器,編譯
速度通常能提高普通編譯過程的5~10倍。
(3) Cmm (C++ with MultiMethods)
參考站點:http://www.op59.net/cmm/cmm-0.28/users.html
這是一種C++語言的擴展。讀入Cmm源代碼輸出C++的源代碼,功能是對C++語言
添加了對multimethod的支持。
(4) The Frost Project
參考站點:http://frost.flewid.de/
Forst使得你能夠在C++程序中像原生的C++特性一樣使用multimethod以及虛函
數參數。它是一個編譯器的外殼。
4.4 測試和調試類
(1) CPPUnit
CppUnit 是個基于 LGPL 的開源項目,最初版本移植自 JUnit,是一個非常優
秀的開源測試框架。CppUnit 和 JUnit 一樣主要思想來源于極限編程。主要功能就
是對單元測試進行管理,并可進行自動化測試。
(2) C++Test
參考站點:http://www.parasoft.com/
C++ Test是一個單元測試工具,它自動化了C和C++類,函數或者組件的測試。
(3) Cantata++
參考站點:http://www.iplbath.com/products/tools/pt400.shtml
設計的目的是為了滿足在合理的經濟開銷下使用這個工具可以讓開發工程師開
展單元測試和集成測試的需求.
(4) Purify
參考站點:http://www-900.ibm.com/cn/software/rational/products/purif
yplus/index.shtml
IBM Rational PurifyPlus是一套完整的運行時分析工具,旨在提高應用程序的
可靠性和性能。PurifyPlus將內存錯誤和泄漏檢測、應用程序性能描述、代碼覆蓋
分析等功能組合在一個單一、完整的工具包中。
(5) BoundsChecker
BoundsChecker是一個C++運行時錯誤檢測和調試工具。它通過在Visual Studi
o內自動化調試過程加速開發并且縮短上市的周期。BoundsChecker提供清楚,詳細
的程序錯誤分析,許多是對C++獨有的并且在static,stack和heap內存中檢測和診
斷錯誤,以及發現內存和資源的泄漏。 (6) Insure++
參考站點:http://www.parasoft.com/
一個自動化的運行時程序測試工具,檢查難以察覺的錯誤,如內存覆蓋,內存泄
漏,內存分配錯誤,變量初始化錯誤,變量定義沖突,指針錯誤,庫錯誤,邏輯錯
誤和算法錯誤等。
(7) GlowCode
參考站點:http://www.glowcode.com/
GlowCode包括內存泄漏檢查,code profiler,函數調用跟蹤等功能。給C++開
發者提供完整的錯誤診斷,和運行時性能分析工具包。
(8) Stack Spy
參考站點:http://www.imperioustech.com/
它能捕捉stack corruption, stack over run, stack overflow等有關棧的錯
誤。
------------------------------------------------------------------------
--------
5,庫
在C++中,庫的地位是非常高的。C++之父 Bjarne Stroustrup先生多次表示了
設計庫來擴充功能要好過設計更多的語法的言論。現實中,C++的庫門類繁多,解決
的問題也是極其廣泛,庫從輕量級到重量級的都有。不少都是讓人眼界大開,亦或
是望而生嘆的思維杰作。由于庫的數量非常龐大,而且限于筆者水平,其中很多并
不了解。所以文中所提的一些庫都是比較著名的大型庫。
5.1 標準庫
標準庫中提供了C++程序的基本設施。雖然C++標準庫隨著C++標準折騰了許多年
,直到標準的出臺才正式定型,但是在標準庫的實現上卻很令人欣慰得看到多種實
現,并且已被實踐證明為有工業級別強度的佳作。
(1) Dinkumware C++ Library
參考站點:http://www.dinkumware.com/
P.J. Plauger編寫的高品質的標準庫。P.J. Plauger博士是Dr. Dobb's程序設
計杰出獎的獲得者。其編寫的庫長期被Microsoft采用,并且最近Borland也取得了
其OEM的license,在其C/C++的產品中采用Dinkumware的庫。
(2) RogueWave Standard C++ Library
參考站點:http://www.roguewave.com/
這個庫在Borland C++ Builder的早期版本中曾經被采用,后來被其他的庫給替
換了。筆者不推薦使用。
(3) SGI STL
參考站點:http://www.roguewave.com/
SGI公司的C++標準模版庫。
(4) STLport
參考站點:http://www.stlport.org/
SGI STL庫的跨平臺可移植版本。
5.2 “準”標準庫 - Boost
參考站點:http://www.boost.org
國內鏡像:http://www.c-view.org/tech/lib/boost/index.htm
Boost庫是一個經過千錘百煉、可移植、提供源代碼的C++庫,作為標準庫的后
備,是C++標準化進程的發動機之一。 Boost庫由C++標準委員會庫工作組成員發起
,在C++社區中影響甚大,其成員已近2000人。 Boost庫為我們帶來了最新、最酷、
最實用的技術,是不折不扣的“準”標準庫。
Boost中比較有名氣的有這么幾個庫:
Regex
正則表達式庫
Spirit
LL parser framework,用C++代碼直接表達EBNF
Graph
圖組件和算法
Lambda
在調用的地方定義短小匿名的函數對象,很實用的functional功能
concept check
檢查泛型編程中的concept
Mpl
用模板實現的元編程框架
Thread
可移植的C++多線程庫
Python
把C++類和函數映射到Python之中
Pool
內存池管理
smart_ptr
5個智能指針,學習智能指針必讀,一份不錯的參考是來自CUJ的文章:
Smart Pointers in Boost,哦,這篇文章可以查到,CUJ是提供在線瀏覽的。
中文版見筆者在《Dr. Dobb's Journal軟件研發雜志》第7輯上的譯文。
Boost總體來說是實用價值很高,質量很高的庫。并且由于其對跨平臺的強調,
對標準C++的強調,是編寫平臺無關,現代C++的開發者必備的工具。但是Boost中也
有很多是實驗性質的東西,在實際的開發中實用需要謹慎。并且很多Boost中的庫功
能堪稱對語言功能的擴展,其構造用盡精巧的手法,不要貿然的花費時間研讀。Bo
ost另外一面,比如Graph這樣的庫則是具有工業強度,結構良好,非常值得研讀的
精品代碼,并且也可以放心的在產品代碼中多多利用。
5.3 GUI
在眾多C++的庫中,GUI部分的庫算是比較繁榮,也比較引人注目的。在實際開
發中,GUI庫的選擇也是非常重要的一件事情,下面我們綜述一下可選擇的GUI庫,
各自的特點以及相關工具的支持。
(1) MFC
大名鼎鼎的微軟基礎類庫(Microsoft Foundation Class)。大凡學過VC++的
人都應該知道這個庫。雖然從技術角度講,MFC是不大漂亮的,但是它構建于Windo
ws API 之上,能夠使程序員的工作更容易,編程效率高,減少了大量在建立 Windo
ws 程序時必須編寫的代碼,同時它還提供了所有一般 C++ 編程的優點,例如繼承
和封裝。MFC 編寫的程序在各個版本的Windows操作系統上是可移植的,例如,在
Windows 3.1下編寫的代碼可以很容易地移植到 Windows NT 或 Windows 95 上。但
是在最近發展以及官方支持上日漸勢微。
(2) QT
參考網站:http://www.trolltech.com/
Qt是Trolltech公司的一個多平臺的C++圖形用戶界面應用程序框架。它提供給
應用程序開發者建立藝術級的圖形用戶界面所需的所用功能。Qt是完全面向對象的
很容易擴展,并且允許真正地組件編程。自從1996年早些時候,Qt進入商業領域,
它已經成為全世界范圍內數千種成功的應用程序的基礎。Qt也是流行的Linux桌面環
境KDE 的基礎,同時它還支持Windows、Macintosh、Unix/X11等多種平臺。
(3) WxWindows
參考網站:http://www.wxwindows.org/
跨平臺的GUI庫。因為其類層次極像MFC,所以有文章介紹從MFC到WxWindows的
代碼移植以實現跨平臺的功能。通過多年的開發也是一個日趨完善的GUI庫,支持同
樣不弱于前面兩個庫。并且是完全開放源代碼的。新近的C++ Builder X的GUI設計
器就是基于這個庫的。
(4) Fox
參考網站:http://www.fox-toolkit.org/
開放源代碼的GUI庫。作者從自己親身的開發經驗中得出了一個理想的GUI庫應
該是什么樣子的感受出發,從而開始了對這個庫的開發。有興趣的可以嘗試一下。
(5) WTL
基于ATL的一個庫。因為使用了大量ATL的輕量級手法,模板等技術,在代碼尺
寸,以及速度優化方面做得非常到位。主要面向的使用群體是開發COM輕量級供網絡
下載的可視化控件的開發者。
(6) GTK
參考網站:http://gtkmm.sourceforge.net/
GTK是一個大名鼎鼎的C的開源GUI庫。在Linux世界中有Gnome這樣的殺手應用。
而GTK就是這個庫的C++封裝版本。
5.4 網絡通信
(1) ACE
參考網站:http://www.cs.wustl.edu/~schmidt/ACE.html
C++庫的代表,超重量級的網絡通信開發框架。ACE自適配通信環境(Adaptive
Communication Environment)是可以自由使用、開放源代碼的面向對象框架,在
其中實現了許多用于并發通信軟件的核心模式。ACE提供了一組豐富的可復用C++包
裝外觀(Wrapper Facade)和框架組件,可跨越多種平臺完成通用的通信軟件任務
,其中包括:事件多路分離和事件處理器分派、信號處理、服務初始化、進程間通
信、共享內存管理、消息路由、分布式服務動態(重)配置、并發執行和同步,等
等。
(2) StreamModule
參考網站:http://www.omnifarious.org/StrMod/
設計用于簡化編寫分布式程序的庫。嘗試著使得編寫處理異步行為的程序更容
易,而不是用同步的外殼包起異步的本質。
(3) SimpleSocket
參考網站:http://home.hetnet.nl/~lcbokkers/simsock.htm
這個類庫讓編寫基于socket的客戶/服務器程序更加容易。
(4) A Stream Socket API for C++
參考網站:http://www.pcs.cnu.edu/~dgame/sockets/socketsC++/sockets.h
tml
又一個對Socket的封裝庫。
5.5 XML
(1) Xerces
參考網站:http://xml.apache.org/xerces-c/
Xerces-C++ 是一個非常健壯的XML解析器,它提供了驗證,以及SAX和DOM API
。XML驗證在文檔類型定義(Document Type Definition,DTD)方面有很好的支持,
并且在2001年12月增加了支持W3C XML Schema 的基本完整的開放標準。
(2) XMLBooster
參考網站:http://www.xmlbooster.com/
這個庫通過產生特制的parser的辦法極大的提高了XML解析的速度,并且能夠產
生相應的GUI程序來修改這個parser。在DOM和SAX兩大主流XML解析辦法之外提供了
另外一個可行的解決方案。
(3) Pull Parser
參考網站:http://www.extreme.indiana.edu/xgws/xsoap/xpp/
這個庫采用pull方法的parser。在每個SAX的parser底層都有一個pull的parse
r,這個xpp把這層暴露出來直接給大家使用。在要充分考慮速度的時候值得嘗試。
(4) Xalan
參考網站:http://xml.apache.org/xalan-c/
Xalan是一個用于把XML文檔轉換為HTML,純文本或者其他XML類型文檔的XSLT處
理器。
(5) CMarkup
參考網站:http://www.firstobject.com/xml.htm
這是一種使用EDOM的XML解析器。在很多思路上面非常靈活實用。值得大家在D
OM和SAX之外尋求一點靈感。
(6) libxml++
http://libxmlplusplus.sourceforge.net/
libxml++是對著名的libxml XML解析器的C++封裝版本
5.6 科學計算
(1) Blitz++
參考網站:http://www.oonumerics.org/blitz/
Blitz++ 是一個高效率的數值計算函數庫,它的設計目的是希望建立一套既具
像C++ 一樣方便,同時又比Fortran速度更快的數值計算環境。通常,用C++所寫出
的數值程序,比 Fortran慢20%左右,因此Blitz++正是要改掉這個缺點。方法是利
用C++的template技術,程序執行甚至可以比Fortran更快。Blitz++目前仍在發展中
,對于常見的SVD,FFTs,QMRES等常見的線性代數方法并不提供,不過使用者可以
很容易地利用Blitz++所提供的函數來構建。
(2) POOMA
參考網站:http://www.codesourcery.com/pooma/pooma
POOMA是一個免費的高性能的C++庫,用于處理并行式科學計算。POOMA的面向對
象設計方便了快速的程序開發,對并行機器進行了優化以達到最高的效率,方便在
工業和研究環境中使用。
(3) MTL
參考網站:http://www.osl.iu.edu/research/mtl/
Matrix Template Library(MTL)是一個高性能的泛型組件庫,提供了各種格式
矩陣的大量線性代數方面的功能。在某些應用使用高性能編譯器的情況下,比如In
tel的編譯器,從產生的匯編代碼可以看出其與手寫幾乎沒有兩樣的效能。
(4) CGAL
參考網站:www.cgal.org
Computational Geometry Algorithms Library的目的是把在計算幾何方面的大
部分重要的解決方案和方法以C++庫的形式提供給工業和學術界的用戶。
5.7 游戲開發
(1) Audio/Video 3D C++ Programming Library
參考網站:http://www.galacticasoftware.com/products/av/
***3D是一個跨平臺,高性能的C++庫。主要的特性是提供3D圖形,聲效支持(S
B,以及S3M),控制接口(鍵盤,鼠標和遙感),XMS。
(2) KlayGE
參考網站:http://home.g365.net/enginedev/
國內游戲開發高手自己用C++開發的游戲引擎。KlayGE是一個開放源代碼、跨平
臺的游戲引擎,并使用Python作腳本語言。KlayGE在LGPL協議下發行。感謝龔敏敏
先生為中國游戲開發事業所做出的貢獻。
(3) OGRE
參考網站:http://www.ogre3d.org
OGRE(面向對象的圖形渲染引擎)是用C++開發的,使用靈活的面向對象3D引擎
。它的目的是讓開發者能更方便和直接地開發基于3D硬件設備的應用程序或游戲。
引擎中的類庫對更底層的系統庫(如:Direct3D和OpenGL)的全部使用細節進行了
抽象,并提供了基于現實世界對象的接口和其它類。
5.8 線程
(1) C++ Threads
參考網站:http://threads.sourceforge.net/
這個庫的目標是給程序員提供易于使用的類,這些類被繼承以提供在Linux環境
中很難看到的大量的線程方面的功能。
(2) ZThreads
參考網站:http://zthread.sourceforge.net/
一個先進的面向對象,跨平臺的C++線程和同步庫。
5.9 序列化
(1) s11n
參考網站:http://s11n.net/
一個基于STL的C++庫,用于序列化POD,STL容器以及用戶定義的類型。
(2) Simple XML Persistence Library
參考網站:http://sxp.sourceforge.net/
這是一個把對象序列化為XML的輕量級的C++庫。
5.10 字符串
(1) C++ Str Library
參考網站:http://www.utilitycode.com/str/
操作字符串和字符的庫,支持Windows和支持gcc的多種平臺。提供高度優化的
代碼,并且支持多線程環境和Unicode,同時還有正則表達式的支持。
(2) Common Text Transformation Library
參考網站:http://cttl.sourceforge.net/
這是一個解析和修改STL字符串的庫。CTTL substring類可以用來比較,插入,
替換以及用EBNF的語法進行解析。
(3) GRETA
參考網站:http://research.microsoft.com/projects/greta/
這是由微軟研究院的研究人員開發的處理正則表達式的庫。在小型匹配的情況
下有非常優秀的表現。
5.11 綜合
(1) P::Classes
參考網站:http://pclasses.com/
一個高度可移植的C++應用程序框架。當前關注類型和線程安全的signal/slot
機制,i/o系統包括基于插件的網絡協議透明的i/o架構,基于插件的應用程序消息
日志框架,訪問sql數據庫的類等等。
(2) ACDK - Artefaktur Component Development Kit
參考網站:http://acdk.sourceforge.net/
這是一個平臺無關的C++組件框架,類似于Java或者.NET中的框架(反射機制,
線程,Unicode,廢料收集,I/O,網絡,實用工具,XML,等等),以及對Java, P
erl, Python, TCL, Lisp, COM 和 CORBA的集成。
(3) dlib C++ library
參考網站:http://www.cis.ohio-state.edu/~kingd/dlib/
各種各樣的類的一個綜合。大整數,Socket,線程,GUI,容器類,以及瀏覽目
錄的API等等。
(4) Chilkat C++ Libraries
參考網站:http://www.chilkatsoft.com/cpp_libraries.asp
這是提供zip,e-mail,編碼,S/MIME,XML等方面的庫。
(5) C++ Portable Types Library (PTypes)
參考網站:http://www.melikyan.com/ptypes/
這是STL的比較簡單的替代品,以及可移植的多線程和網絡庫。
(6) LFC
參考網站:http://lfc.sourceforge.net/
哦,這又是一個嘗試提供一切的C++庫
5.12 其他庫
(1) Loki
參考網站:http://www.moderncppdesign.com/
哦,你可能抱怨我早該和Boost一起介紹它,一個實驗性質的庫。作者在loki中
把C++模板的功能發揮到了極致。并且嘗試把類似設計模式這樣思想層面的東西通過
庫來提供。同時還提供了智能指針這樣比較實用的功能。
(2) ATL
ATL(Active Template Library)
是一組小巧、高效、靈活的類,這些類為創建可互操作的COM組件提供了基本的
設施。
(3) FC++: The Functional C++ Library
這個庫提供了一些函數式語言中才有的要素。屬于用庫來擴充語言的一個代表
作。如果想要在OOP之外尋找另一分的樂趣,可以去看看函數式程序設計的世界。大
師Peter Norvig在 “Teach Yourself Programming in Ten Years”一文中就將函
數式語言列為至少應當學習的6類編程語言之一。
(4) FACT!
參考網站:http://www.kfa-juelich.de/zam/FACT/start/index.html
另外一個實現函數式語言特性的庫
(5) Crypto++
提供處理密碼,消息驗證,單向hash,公匙加密系統等功能的免費庫。
還有很多非常激動人心或者是極其實用的C++庫,限于我們的水平以及文章的篇
幅不能包括進來。在對于這些已經包含近來的庫的介紹中,由于并不是每一個我們
都使用過,所以難免有偏頗之處,請讀者見諒。
------------------------------------------------------------------------
--------
6,書籍
以前熊節先生曾撰文評論相對于Java程序設計語言,C++的好書多如牛毛。榮耀
先生在《程序員》雜志上撰文《C++程序設計之四書五經》也將本領域內幾乎所有的
經典書籍作了全面的介紹,任何關于書的評論此時看來便是很多余的了。個人淺見,
除非你打算以C++作為唯一興趣或者生存之本,一般讀者確實沒有足夠的時間和必要
將20余本書籍全部閱讀。更有參考價值的是榮耀先生的另一篇文章:《至少應該閱
讀的九本C++著作》,可以從下面的地址瀏覽到此文:
http://www.royaloo.com/articles/articles_2003/9CppBooks.htm
下面幾本書對于走在C++初學之路上的讀者是我們最愿意推薦給大家的:
(1) 《C++ Primer》
哦,也許你會抱怨我們為什么不先介紹TCPL,但對于走在學習之路上的入門者,
本書內容更為全面,更為詳細易懂,我們稱它為“C++的超級寶典”并不過分。配有
一本不錯的習題解答《C++ Primer Answer Book》可以輔助你的學習之路。
(2) 《Essential C++》
如果說《C++ Primer》是C++領域的超級寶典,那么此書作為掌握C++的大局觀
當之無愧。正如《.NET大局觀》一書能夠讓讀者全攬.NET,本書講述了C++中最核心
的全部主題。書雖不厚,內容精煉,不失為《C++ Primer》讀者茶余飯后的主題回
顧之作。
(3) 《The C++ Programming Language》
Bjarne為你帶來的C++教程,真正能夠告訴你怎么用才叫真正的C++的唯一一本
書。雖然如同“某某程序設計語言”這樣的書籍會給大家一個內容全攬,入門到精
通的感覺,但本書確實不太適合初學者閱讀。如果你自認為是一名很有經驗的C++程
序員,那至少也要反復咀嚼Bjarne先生所強調的若干內容。
(4) 《Effective C++》,《More Effective C++》
是的,正如一些C++愛好者經常以讀過與沒有讀過上述兩本作品來區分你是否是
C++高手。我們也極力推崇這兩本著作。在各種介紹C++專家經驗的書籍里面,這兩
本是最貼近語言本質,看后最能夠有脫胎換骨感覺的書,讀此書你需每日三省汝身
。
技術書籍仁者見仁,過多的評論反無太多意義,由讀者喜好選擇最適合自己的
書方為上策。
------------------------------------------------------------------------
--------
7,資源網站
正如我們可以通過計算機歷史上的重要人物了解計算機史的發展,C++相關人物
的網站也可以使我們得到最有價值的參考與借鑒,下面的人物我們認為沒有介紹的
必要,只因下面的人物在C++領域的地位眾所周知,我們只將相關的資源進行羅列以
供讀者學習,他們有的工作于貝爾實驗室,有的工作于知名編譯器廠商,有的在不
斷推進語言的標準化,有的為讀者撰寫了多部千古奇作……
(1) Bjarne Stroustrup
http://www.research.att.com/~bs/
(2) Stanley B. Lippman
http://blogs.msdn.com/slippman/
中文版 http://www.zengyihome.net/slippman/index.htm
(3) Scott Meyers
http://www.aristeia.com/
(4) David Musser
http://www.cs.rpi.edu/~musser/
(5) Bruce Eckel
http://www.bruceeckel.com
(6) Nicolai M. Josuttis
http://www.josuttis.com/
(7) Herb Sutter
http://www.gotw.ca/
(8) Andrei Alexandrescu
http://www.coderncppdesign.com/
(9) 侯捷先生
http://www.jjhou.com
(10) 孟巖先生
先生繁忙于工作,癡迷于技術,暫無個人主頁,關于先生的作品可以通過CSDN
的專欄和侯先生的主頁訪問到。
(11) 榮耀先生
http://www.royaloo.com/
(12) 潘愛民先生
http://www.icst.pku.edu.cn/panaimin/pam_homepage.htm
除了上述大師的主頁外,以下的綜合類C++學習參考站點是我們非常愿意向大家
推薦的:
(1) CodeProject
http://www.codeproject.com
(2) CodeGuru
http://www.codeguru.com
(3) Dr. Dobb's Journal
http://www.ddj.com
(4) C/C++ Users Journal
http://www.cuj.com
(5) C維視點
http://www.c-view.org
(6) allaboutprogram
http://www.allaboutprogram.com
其他資料
(1) ISO IEC JTC1/SC22/WG21 - C++:標準C++的權威參考
http://anubis.dkuug.dk/jtc1/sc22/wg21/
(2) C++ FAQ LITE — Frequently Asked Questions: 最為全面的C++FAQ
http://www.sunistudio.com/cppfaq/index.html
C/C++ 新聞組:
你不妨嘗試從這里提問和回答問題,很多不錯的Q&A資源......
(1) .alt.comp.lang.learn.c-c++
這個簡單些,如果你和我一樣是個菜鳥
(2) .comp.lang.c++.moderated
嗯,這個顯然水平高一些
(3) .comp.std.c++
如果你需要討論標準C++相關話題的話
------------------------------------------------------------------------
--------
8,不得不寫的結束語
結束的時候也是總結現狀,展望未來的時候。雖然C++從脫胎于C開始,一路艱
難坎坷的走過來,但是無論如何C++已經取得了工業基礎的地位。文章列舉的大量相關
資源就是最好的證明,而業界的大量用C++寫成的產品代碼以及大量的C++職業工程
師則是最直接的證明。同時,我們可以看到各個高校的計算機專業都開設有C++這門
課程,網絡上對于C++的學習討論也從來都沒有停過。但是,在Java和.NET兩大企業
開發平臺的圍攻下,給人的感覺是C++越來越“不行”了。
C++在面向企業的軟件開發中,在開發便捷性等方面的確要比Java和C#差很多,
其中一個問題是C++語言本身比較復雜,學習曲線比較陡峭,另外一個問題是C++標
準化的時間太長,喪失了很多的壯大機會,耗費了很多精力在廠商的之間的斗爭上
,而C++的標準庫離一個完善的程序開發框架還缺少太多太多的內容,各個第三方的
類庫和框架又在一致性和完整性上沒法和隨平臺提供的框架相提并論。難道C++真的
要退出歷史舞臺了?
從C++目前的活躍程度,以及應用現狀來說是完全能夠肯定C++仍然是軟件工業
的基礎,也不會退出歷史舞臺的。另外從Boost,Loki這些庫中我們也能夠看到C++
的發展非常活躍,對于新技術新思維非常激進,C++仍然廣泛受到關注。從ACE在高
性能通信領域的應用,以及MTL這樣的庫在數值計算領域的出色表現,我們可以看到
C++在高性能應用場合下的不可替代的作用,而嵌入式系統這樣的內存受限開發平臺
,比如Symbian OS上,C++已經發揮著并且將發揮更大的作用。可以預見的是以后的
軟件無論上層的應用怎么變,它的底層核心都會是由C/C++這樣的系統級軟件編寫的
,比如Java虛擬機,.NET Framwork。因為只有這樣的系統級軟件才能完全徹底的發
揮機器的功能。
需要看到的是兩個趨勢,一個趨勢是C++變得更加復雜,更加學院派,通過模板
等有潛力的語法因素構造越來越精巧的庫成為了現代C++的熱點,雖然在利用庫實現
新的編程范式,乃至設計模式等方面很有開創意義,也確實產生了一些能夠便捷開
發的工具,但是更多的是把C++變得更加強大,更加復雜,也更加難懂,似乎也更加
學院派,不得不說它正在向邊緣化道路發展。另一個趨勢是C++在主流的企業應用開
發中已經逐漸退出了,ERP這樣的企業軟件開發中基本上不會考慮C++,除非需要考
慮性能或者和遺留代碼的集成這些因素。C++退守到系統級別語言,成為軟件工業的
基礎是大勢所趨。然而反思一下,真的是退守么?自從STL出現,無數的人風起云涌
的開始支持C++,他們狂呼“我看到深夜消失了,目標軟件工程的出現。我看到了可
維護的代碼。”是的,STL在可維護性下做得如此出色。但是又怎樣呢?STL為C++鋪
平了現代軟件工程的道路,而在上層應用程序軟件開發領域這塊場地早不單獨屬于
C++,很多程序設計語言都做得很出色,瘋狂的支持者會毫不猶豫地說我們應當支持
C++,因為它是世界上最棒的語言。而坦率地說,你的腰桿真的那么硬么?也許只是
在逃避一些事實。C++是優秀的,這不可否認,STL的出現讓C++一度走上了最輝煌的
時刻,然而現在看來……我的一位恩師曾言:真正能夠將STL應用得淋漓盡致的人很
保守地說國內也不超過200人,或許不加入STL能夠使C++向著它應當發展的方向發展
的更好,而現在看來,C++也應當回首到真正屬于他的那一片圣地上……
摘要: C++ / STL
[edit]
Introduction / Help
C++ slides Optimisations, Templates and good use of heritage and polymorphisms (http://www.rz.rwth-aachen.de/computing/events/2002/hpc++/HPC++1.18-1.pdf...
閱讀全文
LuaPlus上手指南(1)
版權所有,轉載請注明出處,勿用于商業用途,謝謝!
作者: 大寶天天見
Blog: http://www.shnenglu.com/singohgod
本人水平有限,有錯請指出,歡迎交流,共同進步!

國內關于Lua的資料實在是太少,為了尋找一個合適的Lua的C++封裝,真是如同大海撈針.在看了眾多資料后鎖定以下幾種:LuaBind ToLua++ LuaPlus.在選擇上頗有諷刺的味道,LuaBind的版本號還沒到1.0,加上網友頗有微詞,放棄.ToLua++本來有朋友推薦,但是怎么都找不到下載,官網就是打不開,無賴放棄.就只有LuaPlus了,看到一些人的評價還行,于是決定就用它吧.
LuaPlus的資料就更少了,連怎么配置怎么調試等什么都沒有,只有沐楓大哥講解了語法方面的一篇文章.啊喲,怎么搞呢,難道又只有硬著頭皮上了?(某偉人曾說過,但凡杰出的事都是硬著頭皮干出來滴)
好了,言歸正傳,下面講講我的經驗吧:
如何編譯
1. 下載
首先到官方網站下載: http://www.luaplus.org/
下載這個: All source code: http://luaplus.org/LuaPlus51_Build1100.zip (我當前的版本,當然越新越好)
2. 剝離
解開下載包,打開 \LuaPlus51_Build1100\Src\LuaPlus 里面是全部源文件,src下是lua的源文件.這里有個令人疑惑的地方,源文件中帶了一些不需要的文件,要剔除去,基本上需要以下這些文件:
1) Lua庫文件:
lapi.c
lapi.h
lauxlib.c
lauxlib.h
lbaselib.c
lcode.c
lcode.h
ldblib.c
ldebug.c
ldebug.h
ldo.c
ldo.h
ldump.c
lfunc.c
lfunc.h
lgc.c
lgc.h
linit.c
|
liolib.c
llex.c
llex.h
llimits.h
lmathlib.c
lmem.c
lmem.h
loadlib.c
lobject.c
lobject.h
lopcodes.c
lopcodes.h
loslib.c
lparser.c
lparser.h
lstate.c
lstate.h
lstring.c
|
lstring.h
lstrlib.c
ltable.c
ltable.h
ltablib.c
ltm.c
ltm.h
lua.h
luaconf.h
lualib.h
lundump.c
lundump.h
lvm.c
lvm.h
lzio.c
lzio.h
print.c
|
2) LuaPlus頭文件:
auxiliar.h
LuaAutoBlock.h
LuaCall.h
LuaFunction.h
LuaHelper.h
LuaHelper_Object.h
LuaHelper_StackObject.h
LuaLink.h
LuaObject.h
LuaObject.inl
LuaPlus.h
LuaPlusCD.h
|
LuaPlusFunctions.h
LuaPlusInternal.h
LuaStackObject.h
LuaStackObject.inl
LuaStackTableIterator.h
LuaState.h
LuaState.inl
LuaStateOutFile.h
LuaTableIterator.h
luathread.h
pt.h
srm.h
|
3) LuaPlus源文件
LuaCall.cpp
LuaObject.cpp
LuaPlus.cpp
LuaPlusAddons.c
LuaPlusFunctions.cpp
LuaPlus_Libs.cpp
LuaStackObject.cpp
|
LuaStackTableIterator.cpp
LuaState.cpp
LuaStateOutFile.cpp
LuaState_DumpObject.cpp
LuaTableIterator.cpp
lwstrlib.c
|
3. 建立項目
然后你就可以在VS中建立一個新項目,靜態鏈接庫的:

分別把需要的文件加進去,之后編譯,應該能通過了.
如何使用
接著講講如何在你的其他項目中使用LuaPlus.
1.必要的配置
你的項目可能是這樣的:

設置GameClient的依賴項是LuaPlusLib
#include "LuaPlus.h"
using namespace LuaPlus;
記得干這事…
2.創建一個狀態
LuaStateOwner state;
今后的操作都圍繞這個state
3.執行腳本
int iret = state->DoFile("test.lua");
返回值為0表示成功,否則不成功.
4.C++中獲取Lua腳本的變量
假設你的test.lua中有:
health = 200;
通過下列方法就可以在C++中得到這個數值
int mytest = state->GetGlobal("health").GetInteger();
5.C++中調用Lua腳本里的函數
假設你的test.lua中有:
function Add(x, y)
return x+y;
end
在C++中需要先聲明這個函數:
LuaFunction<float> Add = state->GetGlobal("Add");
這樣你就有了Add()這個函數,然后就可以像平常一樣使用它了:
float myret = Add(3.14f,5.25f);
6.Lua腳本中調用C++函數
在讀取test.lua之前要先把C++函數注冊到Lua的運行時棧里,這樣在執行lua腳本的時候,才知道執行哪一個函數:
首先有函數:
int LS_PrintNumber(LuaState* state)
{
LuaStack args(state);
if (args[1].IsNumber()) {
printf("%f\n", args[1].GetNumber());
}
return 0;
}
然后注冊這個函數到Lua:
state->GetGlobals().Register("PrintNumber", LS_PrintNumber);
這樣就把LS_PrintNumber映射為Lua中可以使用的函數PrintNumber.
Test.lua腳本中添加調用語句:
PrintNumber(30);
當state->DoFile("test.lua");執行的時候,就執行了C++中的這個函數.
總結
本文介紹了LuaPlus的基本配置方法和使用,希望對你有幫助.下一篇將介紹一些高級特性,如怎樣在VS中調試LuaPlus的腳本,以及對類的操作等.
如果還有任何疑問可以看看下面這個簡單的例子:
/Files/singohgod/LuaPlus_Test.rar