欢迎访问Lu程序设计

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进行运算符重载,需要用函数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):

  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系统内置动态对象进行运算符重载。本文的例子来自Lu系统扩展库LuSystem中的Lu表(有改动,有所简化),参考源代码lu1code.rar,实现对Lu系统内置动态对象lu的数据类型扩展luu(基本类型为 luDynData_lu,扩展类型为 key_luu)。

动态对象lu是一个线性表(简称Lu表,可以保存任何数据,包括任意多个lu表),是Lu脚本的基本数据类型,参考C格式的头文件lu32.h,动态对象lu的结构定义如下:

//动态Lu表
typedef struct luLu
{
    LuData *Lu; //允许为NULL
    luVOID Len; //Lu数据缓冲区长度
} luLu;

Lu表在Lu系统键树中的键值(即基本数据类型BType)为luDynData_lu,参考头文件lu32.h中的定义:

#define luDynData_lu -255 //动态Lu数据

3 代码

  1. #include <stdio.h>
  2. #include <locale.h>
  3. #include "lu32.h"
  4.  
  5. #pragma comment( lib, "lu32.lib" )
  6.  
  7. luKEY key_luu = luPoiKey_User-20; //标识luu的私有键,将对其加锁
  8.  
  9. void _stdcall Del_luu(void *me) //销毁luu的函数,但什么也不做,只为了配合运算符重载,加锁键使用
  10. {
  11. }
  12.  
  13. void _stdcall LuMessage(wchar_t *pch) //输出动态库信息,该函数注册到Lu,由Lu二级函数调用
  14. {
  15. wprintf(L"%s",pch);
  16. }
  17.  
  18. //Lu脚本可调用的二级函数定义
  19. //生成一个luu对象,注册到Lu脚本系统
  20. LuData _stdcall lu_luu(luINT mm,LuData *xx,void *vFor)
  21. {
  22. static wchar_t ErrName[]=L"luu";
  23. luINT i;
  24. luLu *pLu;
  25. LuData a;
  26.  
  27. pLu=(luLu *)NewSysObj(luDynData_lu,mm+1,0);
  28. if(!pLu)
  29. {
  30. a.BType=luStaData_nil; a.VType=luStaData_nil; a.x=0;
  31. return a;
  32. }
  33. for(i=0;i<=mm;i++) pLu->Lu[i]=xx[i];
  34. a.BType=luDynData_lu; a.VType=key_luu; a.x=0; *(luVOID *)&(a.x)=(luVOID)pLu;
  35. FunReObj(vFor);
  36. return a;
  37. }
  38.  
  39. //返回两个luu相加(或者一个luu加其他任意数据)的结果,通过运算符重载间接调用
  40. LuData _stdcall lu_addLuu(luINT mm,LuData *xx,void *vFor)
  41. {
  42. static wchar_t ErrName[]=L"luu +";
  43. luLu *pLu,*pLu0,*pLu1;
  44. luVOID i,j;
  45. LuData a;
  46.  
  47. a.BType=luStaData_nil; a.VType=luStaData_nil; a.x=0;
  48. pLu0=(luLu *)SearchKey((char *)&(xx->x),sizeof(luVOID),luDynData_lu);
  49. pLu1=(luLu *)SearchKey((char *)&((xx+1)->x),sizeof(luVOID),luDynData_lu);
  50. if(pLu0 && pLu1 && xx->BType==luDynData_lu && (xx+1)->BType==luDynData_lu)
  51. {
  52. pLu=(luLu *)NewSysObj(luDynData_lu,pLu0->Len+pLu1->Len,0);
  53. if(!pLu) return a;
  54. for(i=0,j=0;i<pLu0->Len;i++,j++) pLu->Lu[j]=pLu0->Lu[i];
  55. for(i=0;i<pLu1->Len;i++,j++) pLu->Lu[j]=pLu1->Lu[i];
  56. }
  57. else if(pLu0 && xx->BType==luDynData_lu)
  58. {
  59. pLu=(luLu *)NewSysObj(luDynData_lu,pLu0->Len+1,0);
  60. if(!pLu) return a;
  61. for(i=0,j=0;i<pLu0->Len;i++,j++) pLu->Lu[j]=pLu0->Lu[i];
  62. pLu->Lu[j]=xx[1];
  63. }
  64. else if(pLu1 && (xx+1)->BType==luDynData_lu)
  65. {
  66. pLu=(luLu *)NewSysObj(luDynData_lu,pLu1->Len+1,0);
  67. if(!pLu) return a;
  68. for(i=0,j=1;i<pLu1->Len;i++,j++) pLu->Lu[j]=pLu1->Lu[i];
  69. pLu->Lu[0]=xx[0];
  70. }
  71. else
  72. {
  73. return a;
  74. }
  75. a.BType=luDynData_lu; a.VType=key_luu; a.x=0; *(luVOID *)&(a.x)=(luVOID)pLu;
  76. FunReObj(vFor);
  77. return a;
  78. }
  79.  
  80. //输出luu的信息,通过重载函数o间接调用
  81. LuData _stdcall lu_oLuu(luINT mm,LuData *xx,void *vFor)
  82. {
  83. static wchar_t ErrName[]=L"luu o";
  84. luLu *pLu;
  85. luMessage pMessage;
  86. luVOID k=0;
  87. LuData a;
  88.  
  89. a.BType=luStaData_int64; a.VType=luStaData_int64; a.x=0;
  90. pMessage=(luMessage)SearchKey((char *)&k,sizeof(luVOID),luPubKey_User);
  91. if(!pMessage) return a;
  92. pLu=(luLu *)SearchKey((char *)&(xx->x),sizeof(luVOID),luDynData_lu);
  93. if(!pLu) //不可识别的lu对象
  94. {
  95. SetRunErr(1,ErrName,1,0,vFor); return a;
  96. }
  97. pMessage(L"luu{... ...} ");
  98. a.x=13;
  99. return a;
  100. }
  101.  
  102. LuData _stdcall OpLock_luu(luINT m,LuData *Para,void *vFor,int theOperator) //luu的运算符重载函数
  103. {
  104. LuData a;
  105.  
  106. switch(theOperator)
  107. {
  108. case 0: //重载运算符+
  109. return lu_addLuu(m,Para,vFor);
  110. case 44: //重载函数len
  111. Para->VType=luDynData_lu;
  112. a=ExeOperator(m,Para,vFor,theOperator,luDynData_lu); //直接调用基本类型luDynData_lu的len函数
  113. Para->VType=key_luu;
  114. return a;
  115. case 46: //重载函数new
  116. a=ExeOperator(m,Para,vFor,theOperator,luDynData_lu); //直接调用基本类型luDynData_lu的new函数
  117. if(a.VType==luDynData_lu) a.VType=key_luu; //设置扩展类型为自定义的key_luu类型
  118. return a;
  119. case 47: //重载函数oset
  120. case 48: //重载函数oget
  121. Para->VType=luDynData_lu;
  122. a=ExeOperator(m,Para,vFor,theOperator,luDynData_lu); //直接调用基本类型luDynData_lu的oset或oget函数
  123. Para->VType=key_luu;
  124. return a;
  125. case 49: //重载函数o
  126. return lu_oLuu(m,Para,vFor);
  127. default:
  128. SetRunErr(1,L"luu 无法识别的运算符!",theOperator,0,vFor);
  129. break;
  130. }
  131. a.BType=luStaData_nil; a.VType=luStaData_nil; a.x=0;
  132. return a;
  133. }
  134.  
  135. void main(void)
  136. {
  137. void *hFor; //存放表达式句柄,即脚本函数句柄
  138. luINT nPara; //存放表达式的自变量个数
  139. LuData *pPara; //存放输入自变量的数组指针
  140. luINT ErrBegin,ErrEnd; //表达式编译出错的初始位置和结束位置
  141. int ErrCode; //错误代码
  142. LuData Val; //Lu基本数据类型
  143. void *v=NULL; //为了避免编译器报错,初始化为NULL
  144. luVOID k=0; //32位平台上luVOID被定义为__int32;64位平台上luVOID被定义为__int64;k必须赋值为0
  145. wchar_t ForStr[]=L"main(:a,i)= a=luu[22, \"abc\",3.5], o[a], i=-1,while{++i<len(a), o[a(i),\" \"]}"; //字符串表达式
  146.  
  147. setlocale(LC_ALL, "chs"); //设置可以输出中文
  148.  
  149. if(!InitLu()) return; //初始化Lu
  150.  
  151. InsertKey((char *)&k,sizeof(luVOID),luPubKey_User,LuMessage,NULL,NULL,1,v);//使Lu运行时可输出函数信息
  152.  
  153. Val.BType=luStaData_int64; Val.VType=luStaData_int64; Val.x=key_luu; //定义整数常量luu,标识luu对象
  154. SetConst(L"luu",&Val); //设置常量
  155.  
  156. SetFunction(L"luu",lu_luu,-2); //设置二级函数,参数-2表示有不确定的任意多个自变量
  157.  
  158. LockKey(key_luu,Del_luu,OpLock_luu); //在Lu键树中加锁键,只能存储luu类型,但实际上什么也不存储,只为了配合运算符重载
  159.  
  160. ErrCode=LuCom(ForStr,0,0,0,&hFor,&nPara,&pPara,&ErrBegin,&ErrEnd); //编译表达式
  161. if(ErrCode)
  162. {
  163. printf("表达式有错误!错误代码: %d \n",ErrCode);
  164. }
  165. else
  166. {
  167. LuCal(hFor,pPara); //计算表达式的值,hFor即编译得到的表达式句柄
  168. }
  169.  
  170. LockKey(key_luu,NULL,OpLock_luu); //在Lu键树中解锁键
  171.  
  172. FreeLu(); //释放Lu
  173. }

运行结果:

luu{... ...} 22 abc 3.5

4函数说明

本例用到了Lu的10个输出函数:初始化Lu的函数InitLu,释放Lu的函数FreeLu,编译表达式的函数LuCom、计算表达式的函数LuCal、加锁键函数LockKey、注册C/C++函数的函数SetFunction、申请系统内置动态对象函数NewSysObj、插入键值的函数InsertKey、查找键值的函数SearchKey、按指定类型执行运算符重载函数ExeOperator。从这里查看这些函数的说明:Lu编程指南

5 难点分析

在对Lu系统内置动态对象进行运算符重载时,需要:(1)用LockKey加锁一个键(本例为key_luu),但不需要向Lu系统注册任何键值;(2)删除键值的函数(本例为Del_luu)定义为空函数;(3)定义运算符重载函数(本例为OpLock_luu)。

值得一提的是,使用申请系统内置动态对象函数NewSysObj很方便,不仅高效,而且返回的对象已注册到了Lu键树中,不需要自己再进行注册。使用按指定类型执行运算符重载函数ExeOperator也很方便,免去了自己的编码之苦。

(1)如果修改代码中的字符串表达式为(注意C/C++字符串中转义字符 \" 的使用,下同):

main(:a,i)= a=new[luu,3 : 22, "abc",3.5], o[a], i=-1,while{++i<len(a), o[a(i)," "]}

可得到如下结果:

luu{... ...} 22 abc 3.5

(2)如果修改代码中的字符串表达式为:

main(:a,i)= a=luu[22, "abc",3.5], a=55+a+"asd", o[a], i=-1,while{++i<len(a), o[a(i)," "]}

可得到如下结果:

luu{... ...} 55 22 abc 3.5 asd

6 其他

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


版权所有© Lu程序设计 2002-2013,保留所有权利
E-mail: forcal@sina.com  QQ:630715621
最近更新: 2014年01月05日

C/C++对Lu系统内置动态对象进行运算符重载的更多相关文章

  1. 《挑战30天C++入门极限》C++中利用构造函数与无名对象简化运算符重载函数

        C++中利用构造函数与无名对象简化运算符重载函数 在完整描述思想之前,我们先看一下如下的例子,这个例子中的加运算符重载是以非成员函数的方式出现的: //程序作者:管宁  //站点:www.cn ...

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

    欢迎访问Lu程序设计 C/C++注册动态对象到Lu系统并进行运算符重载 1 说明 要演示本文的例子,你必须下载Lu32脚本系统.本文的例子需要lu32.dll.lu32.lib.C格式的头文件lu32 ...

  3. C++学习6-面向对象编程基础(运算符重载、类的派生与继承、命名空间)

    运算符重载 重载的运算符是具有特殊名字的函数:它们的名字由关键字operator和其后要定义的运算符号共同组成.重载的运算符是遵循函数重载的选择原则,根据不同类型或不同参数来选择不同的重载运算符. 运 ...

  4. C#中常用的系统内置委托

    在公共语言运行时(CLR)环境中系统为我们内置了一些常用的委托,包括Action类的委托.Func类的委托.Predicate<T>委托.Comparison<T>委托等等.以 ...

  5. .net学习之新语法学习(匿名类和匿名方法,扩展方法,系统内置委托,Lambda表达式和linq等)

    1.自动属性 Auto-Implemented Properties 2.隐式类型 var  var变量不能作为全局变量使用,因为不能在编译时确定类型 3.参数默认值 和 命名参数 4.对象初始化器 ...

  6. js中内置有对象

    statpot:使用mongo+bootstrap+highcharts做统计报表 最近做了一个统计项目,这个统计项目大致的需求是统计接口的访问速度.客户端会调用一个接口来记录接口的访问情况,我的需求 ...

  7. java 日志脱敏框架 sensitive-v0.0.4 系统内置常见注解,支持自定义注解

    项目介绍 日志脱敏是常见的安全需求.普通的基于工具类方法的方式,对代码的入侵性太强.编写起来又特别麻烦. 本项目提供基于注解的方式,并且内置了常见的脱敏方式,便于开发. 特性 基于注解的日志脱敏. 可 ...

  8. C#中常见的系统内置委托用法详解(抄录)

    C#中常见的系统内置委托 Action类.Func类.Predicate<T>.Comparison<T>委托 Action类的委托 Action委托 封装一个方法,该方法不具 ...

  9. Java日志脱敏框架 sensitive-v0.0.4 系统内置常见注解,支持自定义注解

    项目介绍 日志脱敏是常见的安全需求.普通的基于工具类方法的方式,对代码的入侵性太强.编写起来又特别麻烦. 本项目提供基于注解的方式,并且内置了常见的脱敏方式,便于开发. 特性 基于注解的日志脱敏. 可 ...

随机推荐

  1. Java获取web项目路径

    File f = new File(WebPath.class.getResource("/").getPath()); String path = f.getParentFile ...

  2. poll--wait for some event on a file descriptor

    poll同select,用于监控file descriptor事件,推荐用poll的升级版epool来实现功能,但在简单应用中使用poll更方便. #include <poll.h> in ...

  3. /dev/null脚本中作用

    /dev/null设备文件只有一个作用,往它里面写任何数据都直接丢弃. 因此保证了该命令执行时屏幕上没有任何输出. 在shell中常见. command  > /dev/null   2> ...

  4. Missing artifact jdk.tools:jdk.tools:jar:1.8 pom.xml

    在maven项目中出现下面错误信息: Description Resource Path Location Type Missing artifact jdk.tools:jdk.tools:jar: ...

  5. parted创建LVM

    parted创建LVM 把一块1T硬盘全部设为LVM #parted /dev/sdb >mklabel gpt 由于MBR分区表只支持2T硬盘,所以如果大于2T必须用GPT分区表 >pr ...

  6. js对数字的校验

    //-----------------------------------------------函数(1):允许输入正数和负数的表达式-------------------------------- ...

  7. ubuntu/centos网络配置

    UBUNTU网络配置 配置临时的Ip ifconfig eth0 其中24指的网络掩码24位. vim /etc/network/interfaces 添加下面内容 auto eth0 #开机自动连接 ...

  8. Spring事务:调用同一个类中的方法

    问题: 如果同一个类中有方法:methodA(); methodB().methodA()没有开启事务,methodB()开启了事务 且methodA()会调用methodB(). 那么,method ...

  9. 多媒体开发之h264的三种字节流格式---annexb 哥伦布/mp4 以及还有一种rtp传输流格式

    ------------------------------------author:pkf ------------------------------------------time:2015-1 ...

  10. sql字符串的拼接 (字符串和二进制,erlang的mysql驱动)

    1> list_to_binary(["select * from aa limit","1",",","97"] ...