Journal of Information and Electronics of Guangdong Ocean University Vol.1, No.1, September 2008,pp 48-54 广东海洋大学电子信息学刊 2008 年 9 月第 1 卷 LabVIEW 面向对象编程技术 陈海生 1+ 2, 邓锐 1 ( 广东海洋大学信息学院自动化系, 湛江 524088) 2 ( 广东海洋大学信息学院软件技术系, 湛江 524088) LabVIEW Object-Oriented Programming Technology CHEN Hai-sheng,Deng Rui 1 (Department of Automation,Information College, Guangdong Ocean University, Zhanjiang 524088, China) 2 (Department of Software Technology, Information College, GuanDong Ocean University, Zhanjiang 524088, China) + Corresponding author: Phone: +86-013659723860,, E-mail: cider2002@126.com, http://www.gdou.edu.cn Abstract: Because LabVIEW is simple and flexible, it is widely being applied to the testing and controlling domain. But in the large-scale testing and controlling software development, LabVIEW did not well satisfy the requirement of team cooperation and convenient maintenance, even a little change can lead to a disaster. So National Instruments Company in USA introduces LabVIEW Object-Oriented Programming technology in the version of LabVIEW 8.2. By comparing with C+ + mainly, this paper anatomizes how to apply this programming technology. Keywords:LabVIEW;LVOOP;Object-Oriented Programming 摘要 : 在测控领域,LabVIEW 由于其简单 灵活的特点而受到广泛的应用, 然而使用 LabVIEW 构建大型的测控软件时, 在团队合作 后期维护方面就显出其不足, 甚至一个很小的改动都可能导致灾难性的后果 为此, 美国国家仪器公司在 LabVIEW 8.2 中推出了 LabVIEW 面向对象编程技术, 本文主要是通过对比 C++, 对如何应用该编程技术进行了剖析 关键词 :LabVIEW;LVOOP; 面向对象编程
陈海生, 邓锐 :LabVIEW 面向对象编程技术 49 1 引言 LabVIEW (Laboratory Virtual Instrument Engineering Workbench) 是美国 NI(National Instrument) 公司推出的一种基于 G 语言的虚拟仪器软件开发工具 [1] 对简单的测试任务, 利用 LabVIEW 能快速构建测试平台, 但是对构建复杂的大型的测试软件来说, 随着程序的不断变大, 其中的关系越复杂, 程序就可能变得越脆弱 最后, 甚至一个很小的改动都可能导致灾难性的后果 因此, 在应用 LabVIEW 8.2 版之前的版本创建测控软件时, 工程师们应用 面向组件 的设计概念 (COD, Component Oriented Design): 把系统划分为协作性组件, 尽可能让它们独立工作, 组件间有强的内聚和松散的耦合, 从而使得应用程序的健壮性得到加强 [2] 该方法只是借用了软件工程中的概念, 把组件的设计看成是面向对象语言中的类的设计, 但离面向对象技术还有很大的距离 因此 NI 在 LabVIEW 8.2 版中, 首次推出了 LVOOP (LabVIEW Object-Oriented Programming) 技术, 即 LabVIEW 面向对象编程技术 2 LVOOP 技术剖析 LabVIEW 编程是采用数据流的方式, 现要引进面向对象技术, 首先要考虑的问题是根据自身的特点, 对面向对象技术中的某些概念进行取舍, 下面主要是通过对比 C++ 中的面向对象技术, 对 LVOOP 技术进行剖析 2.1 类和对象在面向对象编程技术中, 类是用来表示通用的特性 假设有一个描述汽车的类, 其定义就是表示各种汽车的通用特性 对象是类的特定实例, 某一辆特定的汽车就是汽车类的一个对象 在 C++ 中, 假设某汽车类 Automobile 定义如下 : class Automobile {public: void start( );void stop ( );private: int door ; int gear;} 汽车的车身上有车门 (door), 排挡上有齿轮 (gear) 车门和齿轮的数据就是汽车类的数据 ; 汽车有启动 (start) 和刹车 (stop) 功能, 启动和刹车功能就是汽车的方法 数据和方法构成了汽车类的定义 在 LVOOP 中, 也是通过类似于 C++ 的方法定义一个类, 图 1 类定义的结构框图类定义的结构框图如图 1 所示 该汽车类的数据存放在 Automobile.ctl 中, 汽车类的方法用 start.vi 和 stop.vi 这两个 vi 来表示 对象是类的特定实例, 指定的某一辆汽车是汽车类的一个特定实现, 称为汽车类的一个对象 对 C++, 利用 Automobile s 语句就能创建一个 Automobile 类对象 s 在 LabVIEW 中, 首先创建一个 main.vi 在该 vi 程序框图处, 右击鼠标, 在弹出的菜单中, 点击 选择 VI, 找到 Automobile.lvclass 并点击, 结果如图 2 所示, 这样就创建一个 Automobile 类对象 图 2 创建一个汽车类对象
50 广东海洋大学电子信息学刊 Vol.1, No.1, September 2008 2.2 构造函数和析构函数在 C++ 中, 随着一个对象的创建, 系统自动调用构造函数对对象进行初始化 如果类中没有声明构造函数, 系统调用默认的构造函数 当类的对象离开其作用域时, 析构函数将会被调用 析构函数的作用是完成一些清理工作, 例如释放从堆中动态分配的内存等 [3] 而在 LabVIEW 中既没有构造函数, 也没有析构函数的概念 LabVIEW 定义类时, 类中的用于定义数据的控件, 如图 1 中的 Automobile.ctl 中的前面板中各种数据的默认值就是数据的初始化 如果不采用默认值作为初始化, 可以在类中创建一个初始化方法 vi, 通过调用该方法就可以实现数据的初始化 2.3 封装类的定义基本上包含数据和方法两部分 C++ 中的类的所有成员 ( 包括方法和数据 ) 都可以设置为公共 保护和私有等封装形式, 而 LabVIEW 类中的数据只有私有封装的形式, 但成员 vi( 即方法 ) 却可以有不同的封装形式, 成员 vi 的访问范围设置选项如下 : 公共 (public) 任何 vi 皆可将该成员 vi 当作子 vi 来调用 ; 保护 (protected) 仅该成员 vi 所在的类及其子类中的 vi 可以调用 ; 私有 (private) 成员 vi 所在的类中的 vi 可以调用 从中可以看出,LabVIEW 中的成员 vi 由于封装形式的不同带来的访问权限的不同, 跟 C++ 中定义的对所有的成员 ( 数据和方法 ) 的各种不同封装形式的访问权限是一致的 在 LabVIEW 中, 外部程序如需访问类中的私有数据, 必须首先创建该类的成员 vi, 在该成员 vi 上对私有数据进行操作 外部程序通过访问该成员 vi, 从而达到对类中私有数据操作的目的 这一点跟 C++ 是一致的 2.4 继承 2.4.1 继承关系在 C++ 中采用基类和派生类来描述继承层次关系 而 LabVIEW 的开发者为了让用户更加清楚明白继承的层次关系, 采用以下术语 [4] : 父类 供其它 LabVIEW 类继承的数据 公共型成员 VI 和保护型成员 VI 的 LabVIEW 类 子类 从父类继承的数据 公共型成员 VI 和保护型成员 VI 的 LabVIEW 类 兄弟类 和一个 LabVIEW 类继承同一个父类的另一个 LabVIEW 类 祖先类 一个 LabVIEW 类的上一层 ( 父类 ) 上二层( 父类的父类 ) 上三层等等 LabVIEW Object 类是所有 LabVIEW 类的始祖 子孙类 - 一个 LabVIEW 类的下一层 ( 子类 ) 下二层( 子类的子类 ) 下三层等等 LabVIEW 中有一个最终类, 就是 LabVIEW Object 类, 通过 LabVIEW Object 类创建的 VI, 能对多个 LabVIEW 类执行通用的操作 JAVA 和 Delphi 中都有最终类, 如在 Delphi 中, 任何类都是 TObject 类的派生类 这允许用户在系统中用 TObject 数据类型替代任何类的数据类型 [5] 而 C++ 中没有最终类, 但 C++ 可以采用模版的方法来实现类似的功能 若一个程序的功能是对某种特定的数据类型进行处理, 则将所处理的数据类型说明为一个参数, 就可把这个程序改写为模版 模版可以让程序对任何其他数据类型进行同样方式的处理 [6]
陈海生, 邓锐 :LabVIEW 面向对象编程技术 51 2.4.2 继承方式在 C++ 中, 继承方式是指派生类如何从基类获得已有的特征, 包括 public private 和 protected 等 3 种方式 public 继承方式下, 基类的公有成员和保护成员在派生类中的类型不变 ; protected 继承方式下, 基类的公有成员和保护成员在派生类中为保护类型 ;private 继承方式下, 基类的公有成员和保护成员在派生类中为私有类型 但是 LabVIEW 中只有 public 继承方式, 只要存在继承关系, 那么必定是 public 继承方式 这是因为 LabVIEW 的开发者认为在实际编程工作中, 保护继承与私有继承的使用是极少的, 它们只在技术理论上有意义 2.4.3 多重继承 C++ 允许多重继承, 即分别从类 A 和类 B 继承得到类 C, 类 C 代表了类 A 和类 B 的合成, 其同时具有两个类的特征 而 LabVIEW 8.2 中没有类似多重继承的机制,LabVIEW 的开发者认为在 LabVIEW 中使用多重继承所能解决的问题和它所带来的问题一样多, 因此没有计划在以后的版本中推出该功能 [7] 2.4.4 实现对私有数据继承的方法 LabVIEW 类中只有私有数据, 然而在实际的编程中往往需要子类从父类继承其私有数据 若创建汽车类 (Automobile.lvclass) 的子类卡车类 (Truck.lvclass), 现需要 卡车类能继承汽车类的 齿轮数量 车门数量 制造 型号 等数据, 同时添加属于其本身的数据, 如布尔型数据 短车厢 和 四轮驱动 等 在面向对象技术中, 私有的成员不能够直接继承, 因此必 须通过间接的方式 卡车类需要继承汽车类的数据, 可以分别 在汽车类中创建 公共 型或 保护 型的成员 Get Doors.vi,Get Gears.vi,Get Make.vi 和 Get Model.vi, 在这里是 将其访问权限设置为 public 该项目结构框图如图 3 所示 Get Gears.vi 的程序框图如图 4 所示 对汽车类中的齿轮数 量数据解除捆绑, 从而得到齿轮数量, 将齿轮数量设置为连线 板的一个输出端 类似地, Get Doors.vi,Get Make.vi 和 Get Model.vi 分别对汽车类中相应的数据解除捆绑 在卡车类中创建一个 get all data.vi 该 vi 的程序框图如图 5 所示 显然卡车类的 get all data.vi 调用了 Get Gears.vi,Get Doors.vi,Get Make.vi 和 Get Model.vi 方法, 这些方法是属于汽车类的, 由于卡车类是汽车类的子类, 所以完全继承了父类的方法, 这些方法就变成了自己方法, 对自己的方法当然有权 图 3 项目结构框图 去访问 用这种方式, 卡车类间接访问汽车类的私有数据 从效果上看, 子类继承了父类的私有数据, 但不是直接继承, 直接继承是不允许的 图 4 Get Gears.vi 程序框图 类似地, 在 C++ 中, 子类为实现对父类私有数据的继承, 可以在子类中创建一个成员函数, 其通过调 用父类的公共或保护型成员来实现对父类私有数据的访问
52 广东海洋大学电子信息学刊 Vol.1, No.1, September 2008 2.5 静态方法在 C++ 中, 类成员或者成员函数声明为 static 的便能实现在类的范围内共享, 这样的成员称作静态成员和静态成员函数, 在 LabVIEW 中没有类似功能的概念 LabVIEW 中使用 静态 (static) 这个术语来描述的方法, 跟 C++ 中描述的 静态 含义完全不同 LabVIEW 认为一个静态方法 (static method) 就是一个简单的子 VI(subVI) 的调用 2.6 动态方法在 LabVIEW 中, 在类层次结构中定义同名的方法, 直到程序运行才可确定调用的是哪一个类的同名 vi, 这样的方法称为动态方法 (dynamic methods), 称为动态方法是为了跟 LabVIEW 中的静态方法相对应 在 LabVIEW 中, 如果子类出现跟父类同名的方法, 那么该方法必须定义为动态方法, 才能通过编译 从继承的观点来看, 子类可以完全继承父类的方法, 也可以是重新编写方法覆盖原来的旧方法 图 6 为 LabVIEW 下的某项目结构框图, 图中 car 类是 vehicle 类的子类, 两者都包含了一个同名的 ShowMember.vi, 图 5 get all data.vi 程序框图该 vi 为动态 vi 创建方法 : 右击 vehicle.lvclass 图标, 通过新建» 动态 VI, 创建一个动态 VI, 保存该 VI 并命名为 ShowMember.vi 在 car 类中创建同名的动态 VI: 在如图 6 所示的项目管理窗口中, 右击 car.lvclass 图标 通过新建» 重写 VI, 创建一个重写 VI 在弹出的对话框中选择需要重写 VI 名称 vehicle.lvclass:showmember.vi 确定之后, 在 car 类中, 即出现一个 ShowMember.vi 2.7 多态 LabVIEW 中的多态 VI(polymorphic VI) 就是该 VI 中包含了多个 subvi, 各个 subvi 具有统一的输入输出接口 在把多态 VI 当成子程序来调用过程中, 该多态 VI 根据其输入端的数据类型来决定调用其中的某个 subvi 在 LabVIEW 中, 动态方法和多态 VI 某种程度上相似 [8] 多态 VI 根据输入的数据的类型来确定调用哪一个 VI; 动态方法在运行时根据动态分配输入终端到达的数据确定调用类层次结构中的哪一个 VI; 动态方法属于 LVOOP 技术范畴, 而多态 VI 在 LVOOP 技术前早就存在 C++ 中的多态跟 LabVIEW 中的多态是一个不同的概念,C++ 中的多态是面向对象技术中一个重要的概念 假设某 C++ 程序定义 car 类是 vehicle 类的派生类, 在类中都定义了同名 ShowMember 函数 程序中的 test 函数声明如下 : 图 6 项目结构框图
陈海生, 邓锐 :LabVIEW 面向对象编程技术 53 void test(vehicle &temp) { temp.showmember( ); } 主程序代码如下 : void main( ) { vehicle a ; car b ; test(a); test(b); } 对象 a 与 b 分别是基类和派生类的对象, 而函数 test 的形参却只是 vehicle 类的引用, 按照类继承的特点, 系统把 car 类对象看作是一个 vehicle 类对象, 因为 car 类的覆盖范围包含 vehicle 类 利用 test 函数实现传递 不同类对象的引用, 分别调用不同类的名称为 ShowMember 的成员函数 因此必须要解决的是正确分辨对象 类型的问题,C++ 提供了多态性 (polymorphism) 的技术来解决此问题 多态技术的实现有赖于虚函数方法, 比如, 把 ShowMember 函数定义为虚方法 在 LabVIEW 中无法创建一个类似上面 C++ 代码中的 test 函数, 该函数的参数是一个 vehicle 类对象的 引用 LabVIEW 中实现上面 C++ 代码所实现的功能是必须明确指定传递的是哪个类的对象, 那么自然就能 明确调用该类的同名 vi 某项目的 main.vi 程序框 图如图 7 所示 : main.vi 把 vehicle1.vi 作为 subvi 来调用, 其实 现的功能是创建一个 vehicle 类对象, 同样,car1.vi 实现的功能是创建一个 car 类对象 vehicle1.vi 和 car1.vi 的输出分别做为 ShowMember.vi 的输入, 因 此,ShowMember.vi 根据其输入的对象类型, 来确 定调用哪个类的 ShowMember.vi 从上面分析看来,LabVIEW 中动态方法的实现 跟 C++ 中派生类重载基类成员函数类似 在 C++ 中, 对于类的重载来说, 明确的不同类的对象, 调用其类的成员函数的时候, 系统是知道如何找到其类的同名成员 比如, 假设 car 类是 vehicle 类的派生类, 都定义了同名的 ShowMember 函数, 主程序图 7 某项目的 main.vi 程序框图代码如下 : void main( ) { vehicle a ; car b ;a. ShowMember( ); b. ShowMember( ); } 在程序中分别使用 a. ShowMember( ) 和 b. ShowMember( ) 语句调用了 vehicle 类和 car 类所定义的 ShowMember 函数 3 结束语 LVOOP 技术是 LabVIEW 在测控领域得到广泛应用催生的产物 对测控工程师来讲, 面向对象技术是专业的计算机编程技术, 而 LVOOP 技术的提出, 让测控工程师很容易地通过图形化的方式来进行面向对象的编程 因此该技术的提出无疑将进一步提升 LabVIEW 的整体优势, 使得基于 LabVIEW 开发的测试软件延伸到大型软件中, 开发更加适合团队合作, 更加方便后期维护 随着 LVOOP 技术的进一步完善, 其应用前景将更加广阔 注 : 本文已发表于 现代计算机 2008 年第 4 期 References: [1] 张仁辉. 基于 ActiveX 技术的 LabVI EW 与 Word 通信实现 [J]. 仪器仪表用户,2007,14(5):92-93 [2] Jon Conway,Steve Watts. 罗霄, 周毅译. 软件工程方法在 LabVIEW 中的应用 [M]. 北京 : 清华大学出版社,2006:26
54 广东海洋大学电子信息学刊 Vol.1, No.1, September 2008 [3] Herber Schildt. 周志荣, 朱德芳, 于秀山等译.C++ 参考大全 ( 第四版 )[M]. 北京 : 电子工业出版社,2003 :191-192 [4] LabVIEW 8.2 帮助. LabVIEW 面向对象编程 [M].National Instruments,2006. [5] 刘艺.Delphi 面向对象编程思想 [M]. 北京 : 机械工业出版社,2003:388 [6] 钱能.C++ 程序设计教程 [M]. 北京 : 清华大学出版社,1999:438 [7] LabVIEW Zone.LabVIEW Object-Oriented Programming: The Decisions Behind the Design[EB/OL].[2007-9-2]. http://zone.ni.com/devzone/cda/tut/p/id/3574 [8] LabVIEW Zone.LabVIEW Object-Oriented Programming FAQ[EB/OL].[2007-9-2]. [9] http://zone.ni.com/devzone/cda/tut/p/id/3573 陈海生男 (1980-) 广东徐闻人, 广东海洋大学信息学院自动化系教师, 工学硕士 主要从事自动控制理论 信号与系统 Matlab 和 C/C++ 程序设计教学工作 主要研究方向包括 : 生产过程在线检测及控制技术, 嵌入式数控技术 邓锐 (1972-), 男, 湖北荆州人, 硕士, 讲师, 主要研究领域为嵌入式系统, 模式识别