欢迎访问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系统内置动态对象进行运算符重载。本文的例子来自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 代码

#include <stdio.h>
#include <locale.h>
#include "lu32.h" #pragma comment( lib, "lu32.lib" ) luKEY key_luu = luPoiKey_User-20; //标识luu的私有键,将对其加锁 void _stdcall Del_luu(void *me) //销毁luu的函数,但什么也不做,只为了配合运算符重载,加锁键使用
{
} void _stdcall LuMessage(wchar_t *pch) //输出动态库信息,该函数注册到Lu,由Lu二级函数调用
{
wprintf(L"%s",pch);
} //Lu脚本可调用的二级函数定义
//生成一个luu对象,注册到Lu脚本系统
LuData _stdcall lu_luu(luINT mm,LuData *xx,void *vFor)
{
static wchar_t ErrName[]=L"luu";
luINT i;
luLu *pLu;
LuData a; pLu=(luLu *)NewSysObj(luDynData_lu,mm+1,0);
if(!pLu)
{
a.BType=luStaData_nil; a.VType=luStaData_nil; a.x=0;
return a;
}
for(i=0;i<=mm;i++) pLu->Lu[i]=xx[i];
a.BType=luDynData_lu; a.VType=key_luu; a.x=0; *(luVOID *)&(a.x)=(luVOID)pLu;
FunReObj(vFor);
return a;
} //返回两个luu相加(或者一个luu加其他任意数据)的结果,通过运算符重载间接调用
LuData _stdcall lu_addLuu(luINT mm,LuData *xx,void *vFor)
{
static wchar_t ErrName[]=L"luu +";
luLu *pLu,*pLu0,*pLu1;
luVOID i,j;
LuData a; a.BType=luStaData_nil; a.VType=luStaData_nil; a.x=0;
pLu0=(luLu *)SearchKey((char *)&(xx->x),sizeof(luVOID),luDynData_lu);
pLu1=(luLu *)SearchKey((char *)&((xx+1)->x),sizeof(luVOID),luDynData_lu);
if(pLu0 && pLu1 && xx->BType==luDynData_lu && (xx+1)->BType==luDynData_lu)
{
pLu=(luLu *)NewSysObj(luDynData_lu,pLu0->Len+pLu1->Len,0);
if(!pLu) return a;
for(i=0,j=0;i<pLu0->Len;i++,j++) pLu->Lu[j]=pLu0->Lu[i];
for(i=0;i<pLu1->Len;i++,j++) pLu->Lu[j]=pLu1->Lu[i];
}
else if(pLu0 && xx->BType==luDynData_lu)
{
pLu=(luLu *)NewSysObj(luDynData_lu,pLu0->Len+1,0);
if(!pLu) return a;
for(i=0,j=0;i<pLu0->Len;i++,j++) pLu->Lu[j]=pLu0->Lu[i];
pLu->Lu[j]=xx[1];
}
else if(pLu1 && (xx+1)->BType==luDynData_lu)
{
pLu=(luLu *)NewSysObj(luDynData_lu,pLu1->Len+1,0);
if(!pLu) return a;
for(i=0,j=1;i<pLu1->Len;i++,j++) pLu->Lu[j]=pLu1->Lu[i];
pLu->Lu[0]=xx[0];
}
else
{
return a;
}
a.BType=luDynData_lu; a.VType=key_luu; a.x=0; *(luVOID *)&(a.x)=(luVOID)pLu;
FunReObj(vFor);
return a;
} //输出luu的信息,通过重载函数o间接调用
LuData _stdcall lu_oLuu(luINT mm,LuData *xx,void *vFor)
{
static wchar_t ErrName[]=L"luu o";
luLu *pLu;
luMessage pMessage;
luVOID k=0;
LuData a; a.BType=luStaData_int64; a.VType=luStaData_int64; a.x=0;
pMessage=(luMessage)SearchKey((char *)&k,sizeof(luVOID),luPubKey_User);
if(!pMessage) return a;
pLu=(luLu *)SearchKey((char *)&(xx->x),sizeof(luVOID),luDynData_lu);
if(!pLu) //不可识别的lu对象
{
SetRunErr(1,ErrName,1,0,vFor); return a;
}
pMessage(L"luu{... ...} ");
a.x=13;
return a;
} LuData _stdcall OpLock_luu(luINT m,LuData *Para,void *vFor,int theOperator) //luu的运算符重载函数
{
LuData a; switch(theOperator)
{
case 0: //重载运算符+
return lu_addLuu(m,Para,vFor);
case 44: //重载函数len
Para->VType=luDynData_lu;
a=ExeOperator(m,Para,vFor,theOperator,luDynData_lu); //直接调用基本类型luDynData_lu的len函数
Para->VType=key_luu;
return a;
case 46: //重载函数new
a=ExeOperator(m,Para,vFor,theOperator,luDynData_lu); //直接调用基本类型luDynData_lu的new函数
if(a.VType==luDynData_lu) a.VType=key_luu; //设置扩展类型为自定义的key_luu类型
return a;
case 47: //重载函数oset
case 48: //重载函数oget
Para->VType=luDynData_lu;
a=ExeOperator(m,Para,vFor,theOperator,luDynData_lu); //直接调用基本类型luDynData_lu的oset或oget函数
Para->VType=key_luu;
return a;
case 49: //重载函数o
return lu_oLuu(m,Para,vFor);
default:
SetRunErr(1,L"luu 无法识别的运算符!",theOperator,0,vFor);
break;
}
a.BType=luStaData_nil; a.VType=luStaData_nil; a.x=0;
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,i)= a=luu[22, \"abc\",3.5], o[a], i=-1,while{++i<len(a), o[a(i),\" \"]}"; //字符串表达式 setlocale(LC_ALL, "chs"); //设置可以输出中文 if(!InitLu()) return; //初始化Lu InsertKey((char *)&k,sizeof(luVOID),luPubKey_User,LuMessage,NULL,NULL,1,v);//使Lu运行时可输出函数信息 Val.BType=luStaData_int64; Val.VType=luStaData_int64; Val.x=key_luu; //定义整数常量luu,标识luu对象
SetConst(L"luu",&Val); //设置常量 SetFunction(L"luu",lu_luu,-2); //设置二级函数,参数-2表示有不确定的任意多个自变量 LockKey(key_luu,Del_luu,OpLock_luu); //在Lu键树中加锁键,只能存储luu类型,但实际上什么也不存储,只为了配合运算符重载 ErrCode=LuCom(ForStr,0,0,0,&hFor,&nPara,&pPara,&ErrBegin,&ErrEnd); //编译表达式
if(ErrCode)
{
printf("表达式有错误!错误代码: %d \n",ErrCode);
}
else
{
LuCal(hFor,pPara); //计算表达式的值,hFor即编译得到的表达式句柄
} LockKey(key_luu,NULL,OpLock_luu); //在Lu键树中解锁键 FreeLu(); //释放Lu
}

运行结果:

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. nand ECC 算法记录

    nandflash ECC 原理记录. nand ECC 全称是Error Checking and correction. 该算法分为列校验和行校验. 列校验有下图所示: * 如上图所示, CP0 ...

  2. size_t ssize_t socklen_t

    size_t 解释一:为了增强程序的可移植性,便有了size_t,它是为了方便系统之间的移植而定义的,不同的系统上,定义size_t可能不一样. 在32位系统上 定义为 unsigned int 也就 ...

  3. JavaScript 闭包原理分析

    本文转载至 http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html 另一篇很好的资料 http://www.k ...

  4. 飞飞影视cms标签

    解析范围: 全站所有模板均可调用 模板名称: 所有模板 调用函数: ff_mysql_vod(参数1:值1;参数2:值2;参数3,值3....;参数n,值n),支持的参数列表如下 * 以下变量名如$v ...

  5. redis调优

    1.先把持久化数据备份一份,然后使用rdb分析工具分析一下大的键值2.然后DBA删除一部分不用的3.然后再配置最大内存 千万不要没清理数据就直接把内存限制较小 那样会触发redis对内存达到限制的处理 ...

  6. Linux 克隆虚拟机引起的“Device eth0 does not seem to be present, delaying initialization”

    Linux 克隆虚拟机引起的“Device eth0 does not seem to be present, delaying initialization” 虚拟机Vmware上克隆了一个Red ...

  7. 关于C++输出中文乱码的解决方案

    把页面编码转换为UTP-8的编码 1.打开G:\vs2013way\VC\vcprojectitems目录 在 file.h newc++file.cpp 中写两句话 #pragma once#pra ...

  8. spring mvc 下载安装

    https://repo.spring.io/webapp/#/artifacts/browse/tree/General/libs-release-local/org/springframework ...

  9. BWT转换对字符串进行编码

    今天看了下bowtie 的论文, 里面描述了BWT转换的过程和bowtie的比对算法: NGS测序数据的数据量非常大, 为了更快的处理, 通常需要对数据进行压缩:而BWT实际上就是一种数据转换方法, ...

  10. OpenGL模板缓冲区与模板测试

    原文地址:http://www.blogjava.net/qileilove/archive/2014/01/23/409269.html 帧缓冲区有许多缓冲区构成,这些缓冲区大致分为: 颜色缓冲区: ...