去年我作了一个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++语言中的"//"。
多行注释中,由"--[["表示注释开始,并且一直延续到"]]"为止。这种注释相当于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.cppblog.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.cppblog.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