C/C++注册动态对象到Lu系统并进行运算符重载
欢迎访问Lu程序设计
C/C++注册动态对象到Lu系统并进行运算符重载
1 说明
要演示本文的例子,你必须下载Lu32脚本系统。本文的例子需要lu32.dll、lu32.lib、C格式的头文件lu32.h,相信你会找到并正确使用这几个文件。
用C/C++编译器创建一个控制台应用程序,复制本文的例子代码直接编译运行即可。
2 关于运算符重载
在本教程系列的开始,介绍了Lu脚本的基本数据结构(详细参考Lu编程指南),即:
struct LuData{ //Lu基本数据结构。
luIFOR x; //luIFOR被定义为64位整数__int64,用于存放数据。对于动态数据类型,对象指针约定保存在x的前4个字节中。
luIFOR y; //存放数据。
luIFOR z; //存放数据。
luKEY VType; //luKEY被定义为32位整数__int32。扩展数据类型,决定重载函数,从而决定了对数据的操作方式。
luKEY BType; //基本数据类型,决定了Lu数据的结构。
};
基本数据类型BType决定了实际的数据结构,而扩展数据类型VType决定了重载函数。若要对某数据类型VType进行运算符重载,需要用函数LockKey对VType加锁,该函数定义如下:
int _stdcall LockKey(luKEY VType,void (_stdcall *DeleteKey)(void *),luOperator OpLock);
VType:被锁定的键的类型。VType>luPubKey_User(公有键、普通键)或者VType<luPriKey_User(私有键)。
DeleteKey:删除键值的函数指针,用于标识要加锁的键。该函数由用户定义,但由Lu调用。若DeleteKey=NULL,表示解锁指定的键。
OpLock:luOperator类型的函数指针,用于对象(用指针标识)的运算符重载,该参数不可为NULL。解锁和加锁所用的OpLock函数必须相同。参考[注1]。
如果加锁或解锁成功,该函数返回0,否则返回非0值。
[注1]:运算符重载函数luOperator函数格式如下(与Lu二级函数相比,仅多了一个参数theOperator):
//m指出数组Para的参数个数(也即操作数的个数,0表示1个,1表示2个,以此类推)。
//hFor为调用该函数的表达式句柄(与二级函数中的表达式句柄相同)。
//theOperator指出运算符的类型或操作类型:+、-、*、/、^、... ...。
LuData (_stdcall *luOperator)(luINT m,LuData *Para,void *hFor,int theOperator); LuData _stdcall OpLock(luINT m,LuData *Para,void *hFor,int theOperator)
{
//... ...
switch(theOperator)
{
case 0: //重载运算符+
//... ...
case 1: //重载运算符-
//... ...
case 2: //重载运算符*
//... ...
case 3: //重载运算符%
//... ...
case 4: //重载运算符/
//... ...
... ...
}
}
如果不打算给加锁的键提供运算符或函数重载功能,须使用函数SetRunErr向Lu报告运行错误。
本文讨论C/C++注册动态对象到Lu系统并进行运算符重载。本文的例子是实现三维向量及部分相关运算(基本类型和扩展类型均为 key_Vector)。实际上,Lu脚本中内置了三维向量(vector)的运算,例如:
(1$2$3) * (7$6$5)
结果为:
(-8.,16.,-8.)
Lu脚本内置的三维向量(vector)是静态数据,但本文的三维向量(Vector)被定义为动态数据,仅为了演示如何将动态对象注册到Lu系统并进行运算符重载。同时,本文还演示了二级函数如何返回一个动态对象;演示了二级函数如何通过参数返回多个动态对象;演示了重载函数new、oset、oget、o的用法;演示了如何由字符串获得一个唯一的整数,以及该整数在Lu脚本中的用法;演示了如何在Lu系统中注册常量和函数;演示了如何接收Lu系统的字符串信息等等。
由于演示的项目较多,本文的例子代码较长。
3 代码
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <locale.h>
#include "lu32.h" #pragma comment( lib, "lu32.lib" ) luKEY key_Vector = luPriKey_User-20; //标识Vector对象的私有键,将对其加锁 //在Lu脚本中,对象成员一般用#开头的字符串标识,例如 #name
luVOID Vector_x; //标识Vector的成员x,在Lu脚本中,设a是一个Vector,则成员x的表示为 a.#x
luVOID Vector_y; //标识Vector的成员y,在Lu脚本中,设a是一个Vector,则成员y的表示为 a.#y
luVOID Vector_z; //标识Vector的成员z,在Lu脚本中,设a是一个Vector,则成员z的表示为 a.#z typedef struct lu_Vector //Vector结构定义,将注册为私有键
{
double x;
double y;
double z;
} lu_Vector; void _stdcall Del_Vector(void *me) //销毁Vector的函数,将注册到Lu系统,实现自动销毁Vector对象
{
free(me);
} void _stdcall LuMessage(wchar_t *pch) //输出动态库信息,该函数注册到Lu,由Lu二级函数调用
{
wprintf(L"%s",pch);
} //定义Lu脚本可调用的二级函数 //演示二级函数如何返回一个动态对象,通过运算符*重载调用
LuData _stdcall Vector_mul(luINT mm,LuData *xx,void *vFor) //计算两个Vector的积,返回一个新Vector
{
static wchar_t ErrName[]=L"Vector *";
lu_Vector *pVector0,*pVector1,*pVector2;
void *NowKey=NULL; //为避免编译器发出警告进行初始化,实际上不需要
char keyname[sizeof(luVOID)];
LuData a; if(xx->BType==key_Vector && (xx+1)->BType==key_Vector)
{
pVector1=(lu_Vector *)SearchKey((char *)&(xx[0].x), sizeof(luVOID), key_Vector);
pVector2=(lu_Vector *)SearchKey((char *)&(xx[1].x), sizeof(luVOID), key_Vector);
if(!pVector1 || !pVector2) goto err;
pVector0=(lu_Vector *)GetBufObj(key_Vector,keyname); //先尝试从缓冲区中获取一个Vector对象
if(!pVector0)
{
pVector0=(lu_Vector *)malloc(sizeof(lu_Vector));
if(!pVector0) goto err;
//在Lu键树中注册键值,参数-1表示注册为指针键,下同
if(InsertKey((char *)&pVector0,-1,key_Vector,pVector0,Del_Vector,NULL,0,NowKey))
{
free(pVector0);
goto err;
}
}
pVector0->x = pVector1->y*pVector2->z - pVector1->z*pVector2->y;
pVector0->y = pVector1->z*pVector2->x - pVector1->x*pVector2->z;
pVector0->z = pVector1->x*pVector2->y - pVector1->y*pVector2->x;
FunReObj(vFor); //通知Lu,该函数将返回一个动态对象
a.BType=key_Vector; a.VType=key_Vector; a.x=0; *(luVOID *)&(a.x)=(luVOID)pVector0;
return a;
}
err: //简化的运行错误处理,实用中要区分错误的不同类型,以方便用户查找错误来源,下同
a.BType=luStaData_nil; a.VType=luStaData_nil; a.x=0;
SetRunErr(1,ErrName,1,0,vFor);
return a;
} //演示二级函数如何通过参数返回多个动态对象,注册到Lu脚本系统
//用法:addsub[a,b,&c,&d],其中a和b是两个Vector对象,c返回a+b,d返回a-b
LuData _stdcall Vector_addsub(luINT mm,LuData *xx,void *vFor) //计算两个Vector的和与差,返回两个新Vector
{
static wchar_t ErrName[]=L"Vector addsub";
lu_Vector *pVector0,*pVector00,*pVector1,*pVector2;
void *NowKey=NULL; //为避免编译器发出警告进行初始化,实际上不需要
char keyname[sizeof(luVOID)];
LuData a; if(xx->BType==key_Vector && (xx+1)->BType==key_Vector)
{
pVector1=(lu_Vector *)SearchKey((char *)&(xx[0].x), sizeof(luVOID), key_Vector);
pVector2=(lu_Vector *)SearchKey((char *)&(xx[1].x), sizeof(luVOID), key_Vector);
if(!pVector1 || !pVector2) goto err;
pVector0=(lu_Vector *)GetBufObj(key_Vector,keyname); //先尝试从缓冲区中获取一个Vector对象
if(!pVector0)
{
pVector0=(lu_Vector *)malloc(sizeof(lu_Vector));
if(!pVector0) goto err;
if(InsertKey((char *)&pVector0,-1,key_Vector,pVector0,Del_Vector,NULL,0,NowKey)) //在Lu键树中注册键值
{
free(pVector0);
goto err;
}
}
pVector00=(lu_Vector *)GetBufObj(key_Vector,keyname); //先尝试从缓冲区中获取一个Vector对象
if(!pVector00)
{
pVector00=(lu_Vector *)malloc(sizeof(lu_Vector));
if(!pVector00)
{
DeleteKey((char *)&pVector0,sizeof(luVOID),key_Vector,Del_Vector,1); //在Lu键树中删除键值,参数1表示先放到缓冲区中
goto err;
}
if(InsertKey((char *)&pVector00,-1,key_Vector,pVector00,Del_Vector,NULL,0,NowKey)) //在Lu键树中注册键值
{
free(pVector0);
DeleteKey((char *)&pVector0,sizeof(luVOID),key_Vector,Del_Vector,1); //在Lu键树中删除键值,参数1表示先放到缓冲区中
goto err;
}
}
pVector0->x = pVector1->x + pVector2->x;
pVector0->y = pVector1->y + pVector2->y;
pVector0->z = pVector1->z + pVector2->z;
pVector00->x = pVector1->x - pVector2->x;
pVector00->y = pVector1->y - pVector2->y;
pVector00->z = pVector1->z - pVector2->z;
FunSaveObj(vFor,NULL,xx); //通知Lu,准备用参数返回动态对象
xx[2].BType=key_Vector; xx[2].VType=key_Vector; xx[2].x=0; *(luVOID *)&(xx[2].x)=(luVOID)pVector0;
FunSaveObj(vFor,xx+2,xx); //通知Lu,参数3返回动态对象:两个Vector的和
xx[3].BType=key_Vector; xx[3].VType=key_Vector; xx[3].x=0; *(luVOID *)&(xx[3].x)=(luVOID)pVector00;
FunSaveObj(vFor,xx+3,xx); //通知Lu,参数4返回动态对象:两个Vector的差
//提示:如果还要通过返回值返回一个动态对象,仍然使用FunReObj函数,本例未通过返回值返回动态对象
return *xx;
}
err:
a.BType=luStaData_nil; a.VType=luStaData_nil; a.x=0;
SetRunErr(1,ErrName,1,0,vFor);
return a;
} //演示重载函数new的用法,通过函数重载调用。new[Vector]可生成一个Vector动态对象
LuData _stdcall Vector_new(luINT mm,LuData *xx,void *vFor) //生成一个Vector对象
{
static wchar_t ErrName[]=L"Vector new";
lu_Vector *pVector0;
void *NowKey=NULL; //为避免编译器发出警告进行初始化,实际上不需要
char keyname[sizeof(luVOID)];
LuData a; pVector0=(lu_Vector *)GetBufObj(key_Vector,keyname); //先尝试从缓冲区中获取一个Vector对象
if(!pVector0)
{
pVector0=(lu_Vector *)malloc(sizeof(lu_Vector));
if(!pVector0) goto err;
if(InsertKey((char *)&pVector0,-1,key_Vector,pVector0,Del_Vector,NULL,0,NowKey)) //在Lu键树中注册键值
{
free(pVector0);
goto err;
}
}
FunReObj(vFor); //该函数将返回一个动态对象
a.BType=key_Vector; a.VType=key_Vector; a.x=0; *(luVOID *)&(a.x)=(luVOID)pVector0;
return a;
err:
a.BType=luStaData_nil; a.VType=luStaData_nil; a.x=0;
SetRunErr(1,ErrName,1,0,vFor);
return a;
} //演示重载函数oset的用法,通过函数重载调用。设a是一个Vector对象,可实现赋值 a.#x=1.1, a.#y=2.2, a.#z=3.3
LuData _stdcall Vector_oset(luINT mm,LuData *xx,void *vFor) //对Vector的元素赋值
{
static wchar_t ErrName[]=L"Vector oset";
lu_Vector *pVector1; if(xx->BType==key_Vector && xx[1].BType==luStaData_struniint && xx[2].BType==luStaData_double)
{
pVector1=(lu_Vector *)SearchKey((char *)&(xx[0].x), sizeof(luVOID), key_Vector);
if(!pVector1) goto err;
if((luVOID)xx[1].x == Vector_x)
{
pVector1->x = *(double *)&(xx[2].x);
}
else if((luVOID)xx[1].x == Vector_y)
{
pVector1->y = *(double *)&(xx[2].x);
}
else if((luVOID)xx[1].x == Vector_z)
{
pVector1->z = *(double *)&(xx[2].x);
}
else
{
goto err;
}
return *xx;
}
err:
SetRunErr(1,ErrName,1,0,vFor);
return *xx;
} //演示重载函数oget的用法,通过函数重载调用。设a是一个Vector对象,可实现取值 a.#x, a.#y, a.#z
LuData _stdcall Vector_oget(luINT mm,LuData *xx,void *vFor) //对Vector的元素赋值
{
static wchar_t ErrName[]=L"Vector oget";
lu_Vector *pVector1;
LuData a; if(xx->BType==key_Vector && xx[1].BType==luStaData_struniint)
{
pVector1=(lu_Vector *)SearchKey((char *)&(xx[0].x), sizeof(luVOID), key_Vector);
if(!pVector1) goto err;
if((luVOID)xx[1].x == Vector_x)
{
*(double *)&(a.x) = pVector1->x;
}
else if((luVOID)xx[1].x == Vector_y)
{
*(double *)&(a.x) = pVector1->y;
}
else if((luVOID)xx[1].x == Vector_z)
{
*(double *)&(a.x) = pVector1->z;
}
else
{
goto err;
}
a.BType=luStaData_double; a.VType=luStaData_double; //返回一个实数
return a;
}
err:
SetRunErr(1,ErrName,1,0,vFor);
return *xx;
} //演示重载函数o的用法,通过函数重载调用。设a是一个Vector对象,o[a]可输出如下信息:Vector x = 1.1, y = 2.3, z = 3.3
LuData _stdcall Vector_o(luINT mm,LuData *xx,void *vFor) //输出Vector的值
{
static wchar_t ErrName[]=L"Vector o";
lu_Vector *pVector1;
wchar_t wchNum[32];
char chNum[32];
luVOID i,k=0;
luMessage pMessage;
LuData a; pMessage=(luMessage)SearchKey((char *)&k,sizeof(luVOID),luPubKey_User);
if(xx->BType==key_Vector)
{
pVector1=(lu_Vector *)SearchKey((char *)&(xx[0].x), sizeof(luVOID), key_Vector);
if(!pVector1) goto err; pMessage(L"Vector x = ");
k = 11; _gcvt_s(chNum,32,pVector1->x,8);
for(i=0;chNum[i];i++) wchNum[i]=chNum[i];
wchNum[i]='\0';
pMessage(wchNum);
k = k + i; pMessage(L", y = ");
k = k + 6; _gcvt_s(chNum,32,pVector1->y,8);
for(i=0;chNum[i];i++) wchNum[i]=chNum[i];
wchNum[i]='\0';
pMessage(wchNum);
k = k + i; pMessage(L", z = ");
k = k + 6; _gcvt_s(chNum,32,pVector1->z,8);
for(i=0;chNum[i];i++) wchNum[i]=chNum[i];
wchNum[i]='\0';
pMessage(wchNum);
k = k + i; pMessage(L" ");
k = k + 2; a.BType=luStaData_int64; a.VType=luStaData_int64; a.x=k; //o函数总是返回输出的字符总数
return a;
}
err:
SetRunErr(1,ErrName,1,0,vFor);
return *xx;
} LuData _stdcall OpLock_Vector(luINT m,LuData *Para,void *hFor,int theOperator) //Vector的运算符重载函数
{
LuData a; switch(theOperator)
{
case 2: //重载运算符*
return Vector_mul(m,Para,hFor);
case 46: //重载函数new
return Vector_new(m-1,Para+1,hFor); //注意参数个数的变化,忽略了new[Vector]中的参数Vector
case 47: //重载函数oset
return Vector_oset(m,Para,hFor);
case 48: //重载函数oget
return Vector_oget(m,Para,hFor);
case 49: //重载函数o
return Vector_o(m,Para,hFor);
default:
a.BType=luStaData_nil; a.VType=luStaData_nil; a.x=0; //没有重载该运算符或者函数,返回nil
SetRunErr(1,L"Vector 无法识别的运算符!",theOperator,0,hFor);
}
return a;
} void main(void)
{
void *hFor; //存放表达式句柄,即脚本函数句柄
luINT nPara; //存放表达式的自变量个数
LuData *pPara; //存放输入自变量的数组指针
luINT ErrBegin,ErrEnd; //表达式编译出错的初始位置和结束位置
int ErrCode; //错误代码
LuData Val; //Lu基本数据类型
void *v=NULL; //为了避免编译器报错,初始化为NULL
luVOID k=0; //32位平台上luVOID被定义为__int32;64位平台上luVOID被定义为__int64;k必须赋值为0
wchar_t ForStr[]=L"main(:a)= a=new[Vector], a.#x=1.1, a.#y=2.2, a.#z=3.3, o[a]"; //字符串表达式 setlocale(LC_ALL, "chs"); //设置可以输出中文 if(!InitLu()) return; //初始化Lu Vector_x = StrToUniInt((char *)L"x",2); //由字符串"x"获得一个唯一的整数,用于标识Vector的成员x
Vector_y = StrToUniInt((char *)L"y",2); //由字符串"y"获得一个唯一的整数,用于标识Vector的成员y
Vector_z = StrToUniInt((char *)L"z",2); //由字符串"z"获得一个唯一的整数,用于标识Vector的成员z Val.BType=luStaData_int64; Val.VType=luStaData_int64; Val.x=key_Vector; //定义整数常量Vector,标识Vector对象
SetConst(L"Vector",&Val); //设置常量 SetFunction(L"addsub",Vector_addsub,3); //设置二级函数addsub,有4个参数 InsertKey((char *)&k,sizeof(luVOID),luPubKey_User,LuMessage,NULL,NULL,1,v);//使Lu运行时可输出函数信息 LockKey(key_Vector,Del_Vector,OpLock_Vector); //在Lu键树中加锁键,只能存储Vector类型 ErrCode=LuCom(ForStr,0,0,0,&hFor,&nPara,&pPara,&ErrBegin,&ErrEnd); //编译表达式
if(ErrCode)
{
printf("表达式有错误!错误代码: %d \n",ErrCode);
}
else
{
LuCal(hFor,pPara); //运行表达式
} LockKey(key_Vector,NULL,OpLock_Vector); //在Lu键树中解锁键 FreeLu(); //释放Lu
}
运行结果:
Vector x = 1.1, y = 2.2, z = 3.3
4函数说明
本例用到了Lu的近一半的输出函数:初始化Lu的函数InitLu,释放Lu的函数FreeLu,编译表达式的函数LuCom、计算表达式的函数LuCal、加锁键函数LockKey、注册常量的函数SetConst、注册C/C++函数的函数SetFunction、由字符串获得一个唯一的整数StrToUniInt、插入键值的函数InsertKey、搜索键值的函数SearchKey、从缓冲区中获取一个对象的函数GetBufObj、从二级函数返回一个动态对象FunReObj、通过二级函数的参数返回多个动态对象FunSaveObj、设置运行错误的函数SetRunErr。从这里查看这些函数的说明:Lu编程指南。
5 难点分析
在给自定义动态类型数据添加运算符重载功能时,需要:(1)用LockKey加锁一个键(本例为key_Vector),自定义的动态类型数据使用该键向Lu系统进行注册,并注册为指针键,以便于Lu系统对垃圾对象的管理(若注册为非指针键,需要自己进行管理);(2)定义删除键值的函数(本例为Del_Vector);(3)定义运算符重载函数(本例为OpLock_Vector)。
在用C/C++进行Lu二级函数设计时,勿忘有关注意实现,参考函数SetFunction的说明。另外,为了提高运行效率,应优先使用函数GetBufObj从缓冲池获取一个动态对象。
代码中定义的Lu二级函数,只有Vector_addsub直接注册到了Lu系统,其余的函数Vector_mul、Vector_new、Vector_oset、Vector_oget、Vector_o是通过Vector对象的运算符重载或者函数重载来间接调用的。注意重载函数Vector_o设计时,o函数除了返回对象信息外,还要返回信息字符串的字符个数。
在Lu脚本中,对象成员一般用#开头的字符串标识,例如 #name 。本例对象Vector的的成员也使用这种表示方法,例如,设a是一个Vector对象,可实现赋值 a.#x=1.1, a.#y=2.2, a.#z=3.3 。实现原理很简单:Lu脚本编译器在编译字符串表达式时,如遇到以#开头的字符串(例如 #name),就使用该字符串生成一个在Lu脚本中唯一的整数(该整数在Lu系统运行期间保持不变),故本程序main函数一开始,就用函数StrToUniInt获取了相关字符串对应的整数值,用以标识Vector对象的成员。
(1)如果修改代码中的字符串表达式为(注意C/C++字符串中转义字符 \" 的使用):
main(:a)= a=new[Vector], a.#x=1., a.#y=2., a.#z=3., o[a.#x, " ",a.#y, " ",a.#z, " "]
可得到如下结果:
1. 2. 3.
(2)如果修改代码中的字符串表达式为:
main(:a,b)= a=new[Vector], a.#x=1., a.#y=2., a.#z=3., b=new[Vector], b.#x=7., b.#y=6., b.#z=5., o[a*b]
可得到如下结果:
Vector x = -8., y = 16., z = -8.
(3)如果修改代码中的字符串表达式为:
main(:a,b,c,d)= a=new[Vector], a.#x=1., a.#y=2., a.#z=3., b=new[Vector], b.#x=7., b.#y=6., b.#z=5., addsub[a,b,&c,&d], o[c,d]
可得到如下结果:
Vector x = 8., y = 8., z = 8. Vector x = -6., y = -4., z = -2.
(4)如果修改代码中的字符串表达式为(注意C/C++字符串中转义字符 \" 的使用):
main(:a,b,i,t0)= t0=clock(), a=new[Vector], a.#x=1., a.#y=2., a.#z=3., b=new[Vector], b.#x=1., b.#y=0., b.#z=0., i=0, while{++i<=1000000, a=a*b}, o[a, " time= ",clock()-t0," ms. "]
可得到如下结果:
Vector x = -0., y = 2., z = 3. time= 531 ms.
本例用Lu脚本内置的静态三维向量vcctor实现,代码为(用OpenLu演示):
main(:a,b,i,t0)= t0=clock(), a=1$2$3, b=1$0$0, i=0, while{++i<=1000000, a=a*b}, o[a, " time= ",clock()-t0," ms. "];
结果为:
{(-0.)$(2.)$(3.)} time= 235 ms.
本例的C++实现为:
#include <iostream>
#include <time.h> using namespace std; class Vector
{
public:
double x;
double y;
double z; Vector(double a=0.0, double b=0.0, double c=0.0)
{
x=a; y=b; z=c;
}
};
Vector operator *(Vector &a, Vector &b)
{
return Vector(a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x);
}
void main(void)
{
Vector a,b;
int i;
clock_t start, end; start = clock();
a.x=1.0; a.y=2.0; a.z=3.0;
b.x=1.0; b.y=0.0; b.z=0.0;
for(i=0;i<1000000;i++)
{
a=a*b;
}
end = clock();
cout << a.x << " " << a.y << " " << a.z << " time= " << end - start << " ms." << endl;
}
结果为:
-0 2 3 time= 16 ms.
考虑到运算符重载时有新对象生成(例如a*b将生成一个新对象),参考以下C++程序:
#include <iostream>
#include <time.h> using namespace std; class Vector
{
public:
double x;
double y;
double z; Vector(double a=0.0, double b=0.0, double c=0.0)
{
x=a; y=b; z=c;
}
};
Vector operator *(Vector &a, Vector &b)
{
return Vector(a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x);
}
void main(void)
{
Vector *pv;
int i;
clock_t start, end; start = clock();
for(i=0;i<1000000;i++)
{
pv = new Vector;
delete pv;
}
end = clock();
cout << " time= " << clock() - start << " ms." << endl;
}
结果为:
time= 312 ms.
看来,C++对运算符重载也是有优化的。
6 其他
你可能注意到了,我的联系方式就在下面,如有不明之处或有什么建议,可随时与我进行联系。
版权所有© Lu程序设计 2002-2013,保留所有权利
E-mail: forcal@sina.com QQ:630715621
最近更新: 2014年01月05日
C/C++注册动态对象到Lu系统并进行运算符重载的更多相关文章
- C/C++对Lu系统内置动态对象进行运算符重载
欢迎访问Lu程序设计 C/C++对Lu系统内置动态对象进行运算符重载 1 说明 要演示本文的例子,你必须下载Lu32脚本系统.本文的例子需要lu32.dll.lu32.lib.C格式的头文件lu32. ...
- Unity3D 创建动态的立方体图系统
Unity3D 创建动态的立方体图系统 这一篇主要是利用上一篇的Shader,通过脚本来完成一个动态的立方体图变化系统. 准备工作如下: 创建一个新的场景.一个球体.提供给场景一个平行光,准备2个立方 ...
- c#注册表对象映射
用于快捷保存与读取注册表,为对应的对象 示例 [RegistryRoot(Name = "superAcxxxxx")] public class Abc : IRegistry ...
- Oracle 用户、对象权限、系统权限
--================================ --Oracle 用户.对象权限.系统权限 --================================ 一.用户与模式 ...
- Oracle笔记之对象权限与系统权限总结
对象权限与系统权限 创建表和创建session是系统权限: 系统管理员是有权限去訪问其它表的 以sys登录 sqlplus sys/on_change_install as sysdba; 创 ...
- 在注册表中查看Windows10系统激活密钥的方法
1 2 3 4 5 6 7 分步阅读 百度经验:jingyan.baidu.com 激活Windows10系统(非自己使用激活密钥激活的系统)以后,我们不一定清楚激活密钥是什么.如果想查看自己电脑 ...
- C#动态对象(dynamic)示例(实现方法和属性的动态)
C#的动态对象的属性实现比较简单,如果要实现动态语言那种动态方法就比较困难,因为对于dynamic对象,扩展方法,匿名方法都是不能用直接的,这里还是利用对象和委托来模拟这种动态方法的实现,看起来有点J ...
- 动态对象创建(二)重载new和delete
动态对象创建(二)重载new和delete 前言 上文我简单介绍了一下动态对象创建的方法,这一篇文章的内容主要是对重载new和delete做一些讲解,也希望能够得到博友们的指点,在这里谢过大家. 通常 ...
- 动态标绘演示系统1.4.3(for ArcGIS Flex)
标绘有API文档啦! 在线浏览 ------------------------------------------------------------------------------------ ...
随机推荐
- (实用)Linux下Eclipse安装配置PyDev
记录备忘. PyDev是Eclipse下支持Python开发的IDE插件,本文介绍安装和配置PyDev插件的过程. 一.安装PyDev插件两种安装方法: 1.在eclipse的Help->Ins ...
- Oracle备份与恢复介绍(物理备份与逻辑备份) 分类: Oracle 2015-07-27 22:59 15人阅读 评论(0) 收藏
算是挺全的了,有命令有真相 原文链接:http://blog.chinaunix.net/uid-354915-id-3525989.html 一.Oracle备份方式分类: Oracle有两类备份方 ...
- WiFidog 广告路由可修改功能更加智能化的几点看法
海蜘蛛Tomato出了mini版,这个对很多做WiFi营销的朋友来说,是一个福音,因为可以直接从FIR302B,一台30多块钱的路由直接刷成Hi-WiFi,而且界面这么漂亮 相信很多人已经对此界面OE ...
- CALayer: autoresizingMask
UIView 可以设定 autoresizingMask,当它的 superView 尺寸改变时,适应何种变化. 不过 CALayer 却没有这个属性,如和做到让 CALayer 和 UIView 一 ...
- hibernate.cfg配置mysql方言
hibernate自动建表,mysql高版本不支持 type=InnoDB 中的type关键字. 应该使用engine关键字 而非type 所以需要在hibernate.cfg.xml中配置方言.否则 ...
- YFCMF 问题
1.菜单不见了,yf.php (main 改为0 ) function tagMenu $parseStr .='echo get_menu("main","'.$to ...
- kafka学习之-server.properties详细说明
http://blog.csdn.net/lizhitao/article/details/25667831 -- 参考文章 http://kafka.apache.org/documentatio ...
- Linux I/O优化 磁盘读写参数设置
关于页面缓存的信息,可以用cat /proc/meminfo 看到.其中的Cached 指用于pagecache的内存大小(diskcache-SwapCache).随着写入缓存页,Dirty 的值会 ...
- python 读取csv文件
python中有一个读写csv文件的包,直接import csv即可 新建test.csv 1.写 import csv with open("test.csv","w& ...
- PyQt环境配置
1.下载python 登录Python官网,目前最新的版本是3.6.3,网址为:https://www.python.org/downloads/release/python-363/ 选中Windo ...