• C/C++注册动态对象到Lu系统并进行运算符重载


    1 说明

        要演示本文的例子,你必须下载Lu32脚本系统。本文的例子需要lu32.dll、lu32.lib、C格式的头文件lu32.h,相信你会找到并正确使用这几个文件。

        用C/C++编译器创建一个控制台应用程序,复制本文的例子代码直接编译运行即可。

    2 关于运算符重载

        在本教程系列的开始,介绍了Lu脚本的基本数据结构(详细参考Lu编程指南),即:

    1. struct LuData{    //Lu基本数据结构。  
    2.     luIFOR x;     //luIFOR被定义为64位整数__int64,用于存放数据。对于动态数据类型,对象指针约定保存在x的前4个字节中。  
    3.     luIFOR y;     //存放数据。  
    4.     luIFOR z;     //存放数据。  
    5.     luKEY  VType; //luKEY被定义为32位整数__int32。扩展数据类型,决定重载函数,从而决定了对数据的操作方式。  
    6.     luKEY  BType; //基本数据类型,决定了Lu数据的结构。  
    7. };  


        基本数据类型BType决定了实际的数据结构,而扩展数据类型VType决定了重载函数。若要对某数据类型VType进行运算符重载,需要用函数LockKeyVType加锁,该函数定义如下:

    int _stdcall LockKey(luKEY VType,void (_stdcall *DeleteKey)(void *),luOperator OpLock);

        VType:被锁定的键的类型。VType>luPubKey_User(公有键、普通键)或者 VType<luPriKey_User(私有键)
        
    DeleteKey:删除键值的函数指针,用于标识要加锁的键。该函数由用户定义,但由Lu调用。若DeleteKey=NULL,表示解锁指定的键。
        
    OpLockluOperator类型的函数指针,用于对象(用指针标识)的运算符重载,该参数不可为NULL。解锁和加锁所用的OpLock函数必须相同。参考[注1]

        如果加锁或解锁成功,该函数返回0,否则返回非0值。

        [注1]:运算符重载函数luOperator函数格式如下(与Lu二级函数相比,仅多了一个参数theOperator):

    1. //m指出数组Para的参数个数(也即操作数的个数,0表示1个,1表示2个,以此类推)。  
    2. //hFor为调用该函数的表达式句柄(与二级函数中的表达式句柄相同)。  
    3. //theOperator指出运算符的类型或操作类型:+、-、*、/、^、... ...。  
    4. LuData (_stdcall *luOperator)(luINT m,LuData *Para,void *hFor,int theOperator);  
    5.   
    6. LuData _stdcall OpLock(luINT m,LuData *Para,void *hFor,int theOperator)  
    7. {  
    8.     //... ...  
    9.     switch(theOperator)  
    10.     {  
    11.     case 0:    //重载运算符+  
    12.         //... ...  
    13.     case 1:    //重载运算符-  
    14.         //... ...  
    15.     case 2:    //重载运算符*  
    16.         //... ...  
    17.     case 3:    //重载运算符%  
    18.         //... ...  
    19.     case 4:    //重载运算符/  
    20.         //... ...  
    21.     ... ...  
    22.     }  
    23. }  


        如果不打算给加锁的键提供运算符或函数重载功能,须使用函数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 代码

    1. #include <stdio.h>  
    2. #include <stdlib.h>  
    3. #include <malloc.h>  
    4. #include <locale.h>  
    5. #include "lu32.h"  
    6.   
    7. #pragma comment( lib, "lu32.lib" )  
    8.   
    9. luKEY key_Vector = luPriKey_User-20;    //标识Vector对象的私有键,将对其加锁  
    10.   
    11. //在Lu脚本中,对象成员一般用#开头的字符串标识,例如 #name  
    12. luVOID Vector_x;    //标识Vector的成员x,在Lu脚本中,设a是一个Vector,则成员x的表示为 a.#x  
    13. luVOID Vector_y;    //标识Vector的成员y,在Lu脚本中,设a是一个Vector,则成员y的表示为 a.#y  
    14. luVOID Vector_z;    //标识Vector的成员z,在Lu脚本中,设a是一个Vector,则成员z的表示为 a.#z  
    15.   
    16. typedef struct lu_Vector    //Vector结构定义,将注册为私有键  
    17. {  
    18.     double x;  
    19.     double y;  
    20.     double z;  
    21. } lu_Vector;  
    22.   
    23. void _stdcall Del_Vector(void *me)  //销毁Vector的函数,将注册到Lu系统,实现自动销毁Vector对象  
    24. {  
    25.     free(me);  
    26. }  
    27.   
    28. void _stdcall LuMessage(wchar_t *pch) //输出动态库信息,该函数注册到Lu,由Lu二级函数调用  
    29. {  
    30.     wprintf(L"%s",pch);  
    31. }  
    32.   
    33. //定义Lu脚本可调用的二级函数  
    34.   
    35. //演示二级函数如何返回一个动态对象,通过运算符*重载调用  
    36. LuData _stdcall Vector_mul(luINT mm,LuData *xx,void *vFor)  //计算两个Vector的积,返回一个新Vector  
    37. {  
    38.     static wchar_t ErrName[]=L"Vector *";  
    39.     lu_Vector *pVector0,*pVector1,*pVector2;  
    40.     void *NowKey=NULL;      //为避免编译器发出警告进行初始化,实际上不需要  
    41.     char keyname[sizeof(luVOID)];  
    42.     LuData a;  
    43.   
    44.     if(xx->BType==key_Vector && (xx+1)->BType==key_Vector)  
    45.     {  
    46.         pVector1=(lu_Vector *)SearchKey((char *)&(xx[0].x), sizeof(luVOID), key_Vector);  
    47.         pVector2=(lu_Vector *)SearchKey((char *)&(xx[1].x), sizeof(luVOID), key_Vector);  
    48.         if(!pVector1 || !pVector2) goto err;  
    49.         pVector0=(lu_Vector *)GetBufObj(key_Vector,keyname);    //先尝试从缓冲区中获取一个Vector对象  
    50.         if(!pVector0)  
    51.         {  
    52.             pVector0=(lu_Vector *)malloc(sizeof(lu_Vector));  
    53.             if(!pVector0) goto err;  
    54.             //在Lu键树中注册键值,参数-1表示注册为指针键,下同  
    55.             if(InsertKey((char *)&pVector0,-1,key_Vector,pVector0,Del_Vector,NULL,0,NowKey))  
    56.             {  
    57.                 free(pVector0);  
    58.                 goto err;  
    59.             }  
    60.         }  
    61.         pVector0->x = pVector1->y*pVector2->z - pVector1->z*pVector2->y;  
    62.         pVector0->y = pVector1->z*pVector2->x - pVector1->x*pVector2->z;  
    63.         pVector0->z = pVector1->x*pVector2->y - pVector1->y*pVector2->x;  
    64.         FunReObj(vFor);     //通知Lu,该函数将返回一个动态对象  
    65.         a.BType=key_Vector; a.VType=key_Vector; a.x=0; *(luVOID *)&(a.x)=(luVOID)pVector0;  
    66.         return a;  
    67.     }  
    68. err:    //简化的运行错误处理,实用中要区分错误的不同类型,以方便用户查找错误来源,下同  
    69.     a.BType=luStaData_nil; a.VType=luStaData_nil; a.x=0;  
    70.     SetRunErr(1,ErrName,1,0,vFor);  
    71.     return a;  
    72. }  
    73.   
    74. //演示二级函数如何通过参数返回多个动态对象,注册到Lu脚本系统  
    75. //用法:addsub[a,b,&c,&d],其中a和b是两个Vector对象,c返回a+b,d返回a-b  
    76. LuData _stdcall Vector_addsub(luINT mm,LuData *xx,void *vFor)   //计算两个Vector的和与差,返回两个新Vector  
    77. {  
    78.     static wchar_t ErrName[]=L"Vector addsub";  
    79.     lu_Vector *pVector0,*pVector00,*pVector1,*pVector2;  
    80.     void *NowKey=NULL;      //为避免编译器发出警告进行初始化,实际上不需要  
    81.     char keyname[sizeof(luVOID)];  
    82.     LuData a;  
    83.   
    84.     if(xx->BType==key_Vector && (xx+1)->BType==key_Vector)  
    85.     {  
    86.         pVector1=(lu_Vector *)SearchKey((char *)&(xx[0].x), sizeof(luVOID), key_Vector);  
    87.         pVector2=(lu_Vector *)SearchKey((char *)&(xx[1].x), sizeof(luVOID), key_Vector);  
    88.         if(!pVector1 || !pVector2) goto err;  
    89.         pVector0=(lu_Vector *)GetBufObj(key_Vector,keyname);    //先尝试从缓冲区中获取一个Vector对象  
    90.         if(!pVector0)  
    91.         {  
    92.             pVector0=(lu_Vector *)malloc(sizeof(lu_Vector));  
    93.             if(!pVector0) goto err;  
    94.             if(InsertKey((char *)&pVector0,-1,key_Vector,pVector0,Del_Vector,NULL,0,NowKey))    //在Lu键树中注册键值  
    95.             {  
    96.                 free(pVector0);  
    97.                 goto err;  
    98.             }  
    99.         }  
    100.         pVector00=(lu_Vector *)GetBufObj(key_Vector,keyname);   //先尝试从缓冲区中获取一个Vector对象  
    101.         if(!pVector00)  
    102.         {  
    103.             pVector00=(lu_Vector *)malloc(sizeof(lu_Vector));  
    104.             if(!pVector00)  
    105.             {  
    106.                 DeleteKey((char *)&pVector0,sizeof(luVOID),key_Vector,Del_Vector,1);    //在Lu键树中删除键值,参数1表示先放到缓冲区中  
    107.                 goto err;  
    108.             }  
    109.             if(InsertKey((char *)&pVector00,-1,key_Vector,pVector00,Del_Vector,NULL,0,NowKey))  //在Lu键树中注册键值  
    110.             {  
    111.                 free(pVector0);  
    112.                 DeleteKey((char *)&pVector0,sizeof(luVOID),key_Vector,Del_Vector,1);    //在Lu键树中删除键值,参数1表示先放到缓冲区中  
    113.                 goto err;  
    114.             }  
    115.         }  
    116.         pVector0->x = pVector1->x + pVector2->x;  
    117.         pVector0->y = pVector1->y + pVector2->y;  
    118.         pVector0->z = pVector1->z + pVector2->z;  
    119.         pVector00->x = pVector1->x - pVector2->x;  
    120.         pVector00->y = pVector1->y - pVector2->y;  
    121.         pVector00->z = pVector1->z - pVector2->z;  
    122.         FunSaveObj(vFor,NULL,xx);   //通知Lu,准备用参数返回动态对象  
    123.         xx[2].BType=key_Vector; xx[2].VType=key_Vector; xx[2].x=0; *(luVOID *)&(xx[2].x)=(luVOID)pVector0;  
    124.         FunSaveObj(vFor,xx+2,xx);   //通知Lu,参数3返回动态对象:两个Vector的和  
    125.         xx[3].BType=key_Vector; xx[3].VType=key_Vector; xx[3].x=0; *(luVOID *)&(xx[3].x)=(luVOID)pVector00;  
    126.         FunSaveObj(vFor,xx+3,xx);   //通知Lu,参数4返回动态对象:两个Vector的差  
    127.         //提示:如果还要通过返回值返回一个动态对象,仍然使用FunReObj函数,本例未通过返回值返回动态对象  
    128.         return *xx;  
    129.     }  
    130. err:  
    131.     a.BType=luStaData_nil; a.VType=luStaData_nil; a.x=0;  
    132.     SetRunErr(1,ErrName,1,0,vFor);  
    133.     return a;  
    134. }  
    135.   
    136. //演示重载函数new的用法,通过函数重载调用。new[Vector]可生成一个Vector动态对象  
    137. LuData _stdcall Vector_new(luINT mm,LuData *xx,void *vFor)  //生成一个Vector对象  
    138. {  
    139.     static wchar_t ErrName[]=L"Vector new";  
    140.     lu_Vector *pVector0;  
    141.     void *NowKey=NULL;      //为避免编译器发出警告进行初始化,实际上不需要  
    142.     char keyname[sizeof(luVOID)];  
    143.     LuData a;  
    144.   
    145.     pVector0=(lu_Vector *)GetBufObj(key_Vector,keyname);    //先尝试从缓冲区中获取一个Vector对象  
    146.     if(!pVector0)  
    147.     {  
    148.         pVector0=(lu_Vector *)malloc(sizeof(lu_Vector));  
    149.         if(!pVector0) goto err;  
    150.         if(InsertKey((char *)&pVector0,-1,key_Vector,pVector0,Del_Vector,NULL,0,NowKey))    //在Lu键树中注册键值  
    151.         {  
    152.             free(pVector0);  
    153.             goto err;  
    154.         }  
    155.     }  
    156.     FunReObj(vFor);     //该函数将返回一个动态对象  
    157.     a.BType=key_Vector; a.VType=key_Vector; a.x=0; *(luVOID *)&(a.x)=(luVOID)pVector0;  
    158.     return a;  
    159. err:  
    160.     a.BType=luStaData_nil; a.VType=luStaData_nil; a.x=0;  
    161.     SetRunErr(1,ErrName,1,0,vFor);  
    162.     return a;  
    163. }  
    164.   
    165. //演示重载函数oset的用法,通过函数重载调用。设a是一个Vector对象,可实现赋值 a.#x=1.1, a.#y=2.2, a.#z=3.3  
    166. LuData _stdcall Vector_oset(luINT mm,LuData *xx,void *vFor) //对Vector的元素赋值  
    167. {  
    168.     static wchar_t ErrName[]=L"Vector oset";  
    169.     lu_Vector *pVector1;  
    170.   
    171.     if(xx->BType==key_Vector && xx[1].BType==luStaData_struniint && xx[2].BType==luStaData_double)  
    172.     {  
    173.         pVector1=(lu_Vector *)SearchKey((char *)&(xx[0].x), sizeof(luVOID), key_Vector);  
    174.         if(!pVector1) goto err;  
    175.         if((luVOID)xx[1].x == Vector_x)  
    176.         {  
    177.             pVector1->x = *(double *)&(xx[2].x);  
    178.         }  
    179.         else if((luVOID)xx[1].x == Vector_y)  
    180.         {  
    181.             pVector1->y = *(double *)&(xx[2].x);  
    182.         }  
    183.         else if((luVOID)xx[1].x == Vector_z)  
    184.         {  
    185.             pVector1->z = *(double *)&(xx[2].x);  
    186.         }  
    187.         else  
    188.         {  
    189.             goto err;  
    190.         }  
    191.         return *xx;  
    192.     }  
    193. err:  
    194.     SetRunErr(1,ErrName,1,0,vFor);  
    195.     return *xx;  
    196. }  
    197.   
    198. //演示重载函数oget的用法,通过函数重载调用。设a是一个Vector对象,可实现取值 a.#x, a.#y, a.#z  
    199. LuData _stdcall Vector_oget(luINT mm,LuData *xx,void *vFor) //对Vector的元素赋值  
    200. {  
    201.     static wchar_t ErrName[]=L"Vector oget";  
    202.     lu_Vector *pVector1;  
    203.     LuData a;  
    204.   
    205.     if(xx->BType==key_Vector && xx[1].BType==luStaData_struniint)  
    206.     {  
    207.         pVector1=(lu_Vector *)SearchKey((char *)&(xx[0].x), sizeof(luVOID), key_Vector);  
    208.         if(!pVector1) goto err;  
    209.         if((luVOID)xx[1].x == Vector_x)  
    210.         {  
    211.             *(double *)&(a.x) = pVector1->x;  
    212.         }  
    213.         else if((luVOID)xx[1].x == Vector_y)  
    214.         {  
    215.             *(double *)&(a.x) = pVector1->y;  
    216.         }  
    217.         else if((luVOID)xx[1].x == Vector_z)  
    218.         {  
    219.             *(double *)&(a.x) = pVector1->z;  
    220.         }  
    221.         else  
    222.         {  
    223.             goto err;  
    224.         }  
    225.         a.BType=luStaData_double; a.VType=luStaData_double; //返回一个实数  
    226.         return a;  
    227.     }  
    228. err:  
    229.     SetRunErr(1,ErrName,1,0,vFor);  
    230.     return *xx;  
    231. }  
    232.   
    233. //演示重载函数o的用法,通过函数重载调用。设a是一个Vector对象,o[a]可输出如下信息:Vector x = 1.1, y = 2.3, z = 3.3  
    234. LuData _stdcall Vector_o(luINT mm,LuData *xx,void *vFor)    //输出Vector的值  
    235. {  
    236.     static wchar_t ErrName[]=L"Vector o";  
    237.     lu_Vector *pVector1;  
    238.     wchar_t wchNum[32];  
    239.     char chNum[32];  
    240.     luVOID i,k=0;  
    241.     luMessage pMessage;  
    242.     LuData a;  
    243.   
    244.     pMessage=(luMessage)SearchKey((char *)&k,sizeof(luVOID),luPubKey_User);  
    245.     if(xx->BType==key_Vector)  
    246.     {  
    247.         pVector1=(lu_Vector *)SearchKey((char *)&(xx[0].x), sizeof(luVOID), key_Vector);  
    248.         if(!pVector1) goto err;  
    249.   
    250.         pMessage(L"Vector x = ");  
    251.         k = 11;  
    252.   
    253.         _gcvt_s(chNum,32,pVector1->x,8);  
    254.         for(i=0;chNum[i];i++) wchNum[i]=chNum[i];  
    255.         wchNum[i]='';  
    256.         pMessage(wchNum);  
    257.         k = k + i;  
    258.   
    259.         pMessage(L", y = ");  
    260.         k = k + 6;  
    261.   
    262.         _gcvt_s(chNum,32,pVector1->y,8);  
    263.         for(i=0;chNum[i];i++) wchNum[i]=chNum[i];  
    264.         wchNum[i]='';  
    265.         pMessage(wchNum);  
    266.         k = k + i;  
    267.   
    268.         pMessage(L", z = ");  
    269.         k = k + 6;  
    270.   
    271.         _gcvt_s(chNum,32,pVector1->z,8);  
    272.         for(i=0;chNum[i];i++) wchNum[i]=chNum[i];  
    273.         wchNum[i]='';  
    274.         pMessage(wchNum);  
    275.         k = k + i;  
    276.   
    277.         pMessage(L"  ");  
    278.         k = k + 2;  
    279.   
    280.         a.BType=luStaData_int64; a.VType=luStaData_int64; a.x=k;    //o函数总是返回输出的字符总数  
    281.         return a;  
    282.     }  
    283. err:  
    284.     SetRunErr(1,ErrName,1,0,vFor);  
    285.     return *xx;  
    286. }  
    287.   
    288. LuData _stdcall OpLock_Vector(luINT m,LuData *Para,void *hFor,int theOperator)  //Vector的运算符重载函数  
    289. {  
    290.     LuData a;  
    291.   
    292.     switch(theOperator)  
    293.     {  
    294.     case 2: //重载运算符*  
    295.         return Vector_mul(m,Para,hFor);  
    296.     case 46:    //重载函数new  
    297.         return Vector_new(m-1,Para+1,hFor);     //注意参数个数的变化,忽略了new[Vector]中的参数Vector  
    298.     case 47:    //重载函数oset  
    299.         return Vector_oset(m,Para,hFor);  
    300.     case 48:    //重载函数oget  
    301.         return Vector_oget(m,Para,hFor);  
    302.     case 49:    //重载函数o  
    303.         return Vector_o(m,Para,hFor);  
    304.     default:  
    305.         a.BType=luStaData_nil; a.VType=luStaData_nil; a.x=0;    //没有重载该运算符或者函数,返回nil  
    306.         SetRunErr(1,L"Vector 无法识别的运算符!",theOperator,0,hFor);  
    307.     }  
    308.     return a;  
    309. }  
    310.   
    311. void main(void)  
    312. {  
    313.     void *hFor;     //存放表达式句柄,即脚本函数句柄  
    314.     luINT nPara;        //存放表达式的自变量个数  
    315.     LuData *pPara;      //存放输入自变量的数组指针  
    316.     luINT ErrBegin,ErrEnd;  //表达式编译出错的初始位置和结束位置  
    317.     int ErrCode;        //错误代码  
    318.     LuData Val;     //Lu基本数据类型  
    319.     void *v=NULL;       //为了避免编译器报错,初始化为NULL  
    320.     luVOID k=0;     //32位平台上luVOID被定义为__int32;64位平台上luVOID被定义为__int64;k必须赋值为0  
    321.     wchar_t ForStr[]=L"main(:a)= a=new[Vector], a.#x=1.1, a.#y=2.2, a.#z=3.3, o[a]";    //字符串表达式  
    322.   
    323.     setlocale(LC_ALL, "chs");   //设置可以输出中文  
    324.   
    325.     if(!InitLu()) return;   //初始化Lu  
    326.   
    327.     Vector_x = StrToUniInt((char *)L"x",2); //由字符串"x"获得一个唯一的整数,用于标识Vector的成员x  
    328.     Vector_y = StrToUniInt((char *)L"y",2); //由字符串"y"获得一个唯一的整数,用于标识Vector的成员y  
    329.     Vector_z = StrToUniInt((char *)L"z",2); //由字符串"z"获得一个唯一的整数,用于标识Vector的成员z  
    330.   
    331.     Val.BType=luStaData_int64; Val.VType=luStaData_int64; Val.x=key_Vector; //定义整数常量Vector,标识Vector对象  
    332.     SetConst(L"Vector",&Val);   //设置常量  
    333.   
    334.     SetFunction(L"addsub",Vector_addsub,3); //设置二级函数addsub,有4个参数  
    335.   
    336.     InsertKey((char *)&k,sizeof(luVOID),luPubKey_User,LuMessage,NULL,NULL,1,v);//使Lu运行时可输出函数信息  
    337.   
    338.     LockKey(key_Vector,Del_Vector,OpLock_Vector);   //在Lu键树中加锁键,只能存储Vector类型  
    339.   
    340.     ErrCode=LuCom(ForStr,0,0,0,&hFor,&nPara,&pPara,&ErrBegin,&ErrEnd);  //编译表达式  
    341.     if(ErrCode)  
    342.     {  
    343.         printf("表达式有错误!错误代码: %d  ",ErrCode);  
    344.     }  
    345.     else  
    346.     {  
    347.         LuCal(hFor,pPara);  //运行表达式  
    348.     }  
    349.   
    350.     LockKey(key_Vector,NULL,OpLock_Vector); //在Lu键树中解锁键  
    351.   
    352.     FreeLu();           //释放Lu  
    353. }  


    运行结果:

    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重生之大文豪www.dwhao.com搜索键值的函数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_mulVector_newVector_osetVector_ogetVector_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++实现为:

    1. #include <iostream>  
    2. #include <time.h>  
    3.   
    4. using namespace std;  
    5.   
    6. class Vector  
    7. {  
    8. public:  
    9.     double x;  
    10.     double y;  
    11.     double z;  
    12.   
    13.     Vector(double a=0.0, double b=0.0, double c=0.0)  
    14.     {  
    15.         x=a; y=b; z=c;  
    16.     }  
    17. };  
    18. Vector operator *(Vector &a, Vector &b)  
    19. {  
    20.     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);  
    21. }  
    22. void main(void)  
    23. {  
    24.     Vector a,b;  
    25.     int i;  
    26.     clock_t start, end;  
    27.   
    28.     start = clock();  
    29.     a.x=1.0; a.y=2.0; a.z=3.0;  
    30.     b.x=1.0; b.y=0.0; b.z=0.0;  
    31.     for(i=0;i<1000000;i++)  
    32.     {  
    33.         a=a*b;  
    34.     }  
    35.     end = clock();  
    36.     cout << a.x << " " << a.y << " " << a.z << " time= " << end - start << " ms." << endl;  
    37. }  


        结果为:

    -0 2 3 time= 16 ms.

        考虑到运算符重载时有新对象生成(例如a*b将生成一个新对象),参考以下C++程序:

    1. #include <iostream>  
    2. #include <time.h>  
    3.   
    4. using namespace std;  
    5.   
    6. class Vector  
    7. {  
    8. public:  
    9.     double x;  
    10.     double y;  
    11.     double z;  
    12.   
    13.     Vector(double a=0.0, double b=0.0, double c=0.0)  
    14.     {  
    15.         x=a; y=b; z=c;  
    16.     }  
    17. };  
    18. Vector operator *(Vector &a, Vector &b)  
    19. {  
    20.     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);  
    21. }  
    22. void main(void)  
    23. {  
    24.     Vector *pv;  
    25.     int i;  
    26.     clock_t start, end;  
    27.   
    28.     start = clock();  
    29.     for(i=0;i<1000000;i++)  
    30.     {  
    31.         pv = new Vector;  
    32.         delete pv;  
    33.     }  
    34.     end = clock();  
    35.     cout << " time= " << clock() - start << " ms." << endl;  
    36. }  


        结果为:

     time= 312 ms.

        看来,C++对运算符重载也是有优化的。

    6 其他

        你可能注意到了,我的联系方式就在下面,如有不明之处或有什么建议,可随时与我进行联系。

  • 相关阅读:
    计数器
    ToString()方法的应用
    js阻止提交表单(post)
    跟随鼠标单击移动的div
    js实现CheckBox全选全不选
    生成n~m的随机数
    洛谷试炼场 动态规划TG.lv(3)
    洛谷试炼场 动态规划TG.lv(2)
    无题十一
    无题十
  • 原文地址:https://www.cnblogs.com/haichun/p/3508774.html
Copyright © 2020-2023  润新知