Company Events Academic NI Developer Zone Support Solutions Products & Services Contact NI MyNI

Creating LabVIEW Classes

LabVIEW 8.5 Help
August 2007

NI Part Number:
371361D-01

»View Product Info

You create user-defined data types in LabVIEW by creating LabVIEW classes. LabVIEW classes define data associated with an object, as well as the methods that define the actions you can perform on the data. The benefits of encapsulation and inheritance allow you to create modular code that is easy to change without affecting code throughout the application.

In LabVIEW, the data of a class is private, which means only VIs that are members of the class can access the data. You define the data of the class in the private data control. When you create and save a LabVIEW class, LabVIEW creates a class library file (.lvclass) that defines a new data type. The class library file records the private data control and information about any member VIs you create, such as a list of the VIs and various properties of the VIs. The class library is similar to the project library (.lvlib). However, the class library defines a new data type.

The private data control is a unique class library file that defines a cluster of data for the new data type and is the data on the class wire. LabVIEW does not save the private data control on disk. Instead, LabVIEW saves it inside the class library file. Saving the private data control inside the class library file allows LabVIEW to ensure that you never use the wrong private data with the class definition.

Tip   You can create a directory on disk named the same as the LabVIEW class to save the class library file, class member VIs, and class custom default probes. You can include the files that the class library owns in the directory. If you include files for more than one class library in the same directory, conflicts might occur if you try to include VIs of the same name in different class libraries. Naming conflicts can occur in the development process when you override dynamic member VIs.

Encapsulation

Each LabVIEW class consists of a cluster of data and methods to read and write to that cluster. The data of a LabVIEW class is always private or hidden from VIs that are not members of the class. To access the private data, you create methods, in the form of member VIs of the class, to perform functions on the private data of the class. Encapsulation is the consolidation of data and methods into a class where the data is accessible only through class member VIs. Encapsulation allows you to create modular blocks of code that you can easily update or change without affecting other sections of code within the application.

While data of the class is always private, you can expose member VIs to the user in varying degrees. You can set the access scope of a method to the following options:

  • Public scope—Any VI can call the member VI as a subVI.
  • Protected scope—Only VIs within the same class or a descendant class can call the member VI. Protected member VIs display a dark yellow key glyph in the Project Explorer window.
  • Private scope—Only VIs within the same class can call the member VI. Private member VIs display a red key glyph in the Project Explorer window.
  • Not specified—This option appears only when you select a folder. The folder does not have access items specified. Access is public. By default, folders in a class do not have access specified, which means the folders are publicly accessible.
    Note  If you specify access options for a folder, the access setting applies to all items in the folder and overrides access options for individual items in the folder.

Developers of applications that use LabVIEW classes, or LabVIEW class users, can create a VI outside of the LabVIEW class and use public member VIs as subVIs on the block diagram. Public member VIs allow LabVIEW class users to manipulate the private data of the class. The developers who create the LabVIEW classes, or LabVIEW class developers, can use private and protected member VIs on block diagrams of member VIs to manipulate the private data of the class that is not exposed to LabVIEW class users. Limiting the entry points of a class can make it easier for all developers and programmers to debug code because you decrease the opportunity for introducing errors to the data.

Refer to the following projects for examples of encapsulation and access scope in LabVIEW classes.

  • labview\examples\lvoop\DataEncapsulation\Data Encapsulation.lvproj 
  • labview\examples\lvoop\AccessScope\Access Scope.lvproj 

Defining Private Data Controls

LabVIEW creates a private data control of the class automatically when you create a LabVIEW class. In the following Project Explorer window, notice that the LabVIEW class icon is a colored cube. The cube represents a LabVIEW class. The icon of the private data control is a colored cube with a green cylinder. The cylinder represents data storage. Also, the icon of the private data control displays a red key glyph indicating the control is private.

You use the Control Editor window to customize the private data control of a class. LabVIEW displays the Control Editor window when you double-click the private data control of the class in the Project Explorer window. You can place controls and indicators in the Cluster of class private data to define the private data type of a LabVIEW class. The default values you set for the controls in the Cluster of class private data are the default values for the class.

In the following example, the data type of the Automobile class contains two numerics, Number of Gears and Number of Doors, and two strings, Make and Model.

Note  You may leave the Cluster of class private data empty if the class does not need any private data.

To create an icon that visually represents the class on the block diagram or front panel, right-click the icon in the upper right corner of the private data control and select Edit Icon from the shortcut menu. Because LabVIEW overlays a class mask to the icon you create in the Icon Editor dialog box, use an image no larger than 32 pixels wide by 19 pixels high for the class icon to avoid the mask obscuring any part of the class icon. You also can edit the class icon to use a different mask on the General Settings page of the Class Properties dialog box. The following images display the class mask (1), the class icon (2), and the class control on the block diagram (3), respectively.

Creating Member VIs

Create member VIs to perform operations on the private data of the class. Member VIs are the methods of the LabVIEW class. Member VIs are members of the LabVIEW class in which you create them and appear in the Project Explorer window under the private data control of the class.

LabVIEW defines data of the class as a cluster. Any member VI can read or write to the cluster of class data. LabVIEW provides a shortcut to create a VI to access individual elements of the cluster. These accessor VIs are members of the LabVIEW class and can read from or write to class data. If you create an accessor VI to read class data, LabVIEW unbundles the class data for you, as seen in the following image.

If you create an accessor VI to write to class data, LabVIEW bundles the new value into the class data for you, as seen in the following image.

You also can use the Unbundle and Unbundle By Name functions to unbundle private data of the class on the block diagram of a member VI. Use the Bundle and Bundle By Name functions to re-bundle the cluster of private data after you access and manipulate it. Because the data of a class is private, the Bundle and Unbundle nodes break if you try to use them with class data on the block diagram of a non-member VI.

Note  Consider using the Bundle By Name and Unbundle By Name functions instead of Bundle or Unbundle whenever possible to prevent VIs from breaking if you insert a new element into the cluster of private data.

You can create a member VI in several ways. Right-click the class and select among the following shortcut menu items:

  • New»VI—Opens a blank member VI.
  • New»VI from Dynamic Dispatch Template—LabVIEW populates the new member VI with error in and error out clusters, a Case structure for error handling, the input LabVIEW class, and the output LabVIEW class. LabVIEW sets both the input and output terminals as dynamic on the connector pane of the VI.
  • New»VI from Static Dispatch Template—LabVIEW populates the new member VI with error in and error out clusters, a Case structure for error handling, the input LabVIEW class, and the output LabVIEW class. Contrary to creating a dynamic dispatch VI, LabVIEW does not set the input and output terminals as dynamic on the connector pane of the static dispatch VI.
  • New»VI for Data Member Access—Opens the Create Accessor dialog box. Use this dialog box to quickly create member VIs that can access the LabVIEW class data.
    Note  You must save a new LabVIEW class before using this option. LabVIEW dims the VI for Data Member Access option if you have not saved the new class.
  • New»VI for Override—Creates a member VI that overrides an ancestor member VI. LabVIEW uses the ancestor VI icon and overlays the icon mask of the child class to create the icon of the new VI.
    Note  LabVIEW dims the New»VI for Override option if there is not a valid member VI to override. Refer to the Inheritance section for more information about dynamic VIs and overriding.

Inheritance

Inheritance allows you to use an existing class as the starting point for a new class. If you create a new LabVIEW class and set it to inherit data and member VIs from another class, the new class can use the public and protected member VIs of the class from which it inherits. It also can add its own data and member VIs to increase its functionality. For example, the private data of the Automobile class contains Number of Gears, Number of Doors, Make, and Model. If you create a new class and name it Truck, you can set Truck to inherit the data from Automobile as well as add the Boolean data Short Bed? and Four Wheel Drive?, as shown in the following image. The private data of the Truck class now contains Number of Gears, Number of Doors, Make, Model, Short Bed? and Four Wheel Drive?.

When you bundle or unbundle a LabVIEW class, the nodes show terminals only for the private data of the current class, not for any of the data the class inherits from the ancestor classes. Ancestor data is private and you modify it by using functions the ancestor class provides through member VIs. Member VIs of descendant classes may call any of the public member VIs, just like any VI in LabVIEW. But the descendant class member VIs also can call the protected member VIs of an ancestor class. When you designate an ancestor member VI as protected, member VIs of any child class may call the method but no VI outside of the inheritance hierarchy may do so. If you want to access Number of Gears of class Automobile in class Truck, you can create a public or protected member VI in class Automobile called Get Gears.vi. You can unbundle class Automobile on the block diagram of Get Gears.vi, exposing Number of Gears. You then can assign Number of Gears to an output terminal in the connector pane, which allows you to access specific private data of class Automobile in a descendant class, such as class Truck.

Note  LabVIEW classes cannot call the private member VIs of another LabVIEW class even from a parent class. You can use private member VIs only on block diagrams of other member VIs within the same class.

LabVIEW Object

The phrase LabVIEW Object is the name of a specific class. LabVIEW Object is the ultimate ancestor of the inheritance tree in object-oriented programming in LabVIEW. By default, all LabVIEW classes inherit from LabVIEW Object. You can use LabVIEW Object to create VIs that can conduct generic operations on multiple LabVIEW classes. For example, if you create an array of LabVIEW classes, the data of the array is heterogeneous because it can contain elements of the class type of the array or any descendant class. If an array is of type LabVIEW Object, it can contain Automobile, Truck, and Bowling Ball. Class Bowling Ball does not inherit from class Automobile or class Truck, so LabVIEW creates an array of the most common ancestor base class, in this case LabVIEW Object.

The following image displays Array of Automobile, an array that contains class Automobile and class Truck. Because Truck inherits from Automobile, the common ancestor base class of this array is type Automobile. The image also displays Array of LabVIEW Object that contains classes LabVIEW Object, Automobile, Truck, and Bowling Ball. Bowling Ball does not inherit from Automobile or Truck, but all three ultimately inherit from LabVIEW Object; therefore, Array of LabVIEW Object is of type LabVIEW Object.

Setting Inheritance

All LabVIEW classes inherit from LabVIEW Object by default. If you want to change which class another class inherits from, you must change the inheritance after you create the involved classes. You can configure the inheritance and other options of the class in the Class Properties dialog box. You can view the hierarchy of LabVIEW classes in the LabVIEW Class Hierarchy window. The class inheritance hierarchy can include the following types of classes.

  • Parent class—LabVIEW class from which other LabVIEW classes inherit data and public and protected member VIs.
  • Child class—LabVIEW class that inherits the data and public and protected member VIs of the parent class.
  • Sibling class—LabVIEW class that shares the same parent class as another LabVIEW class.
  • Ancestor class—LabVIEW class that is the parent, grandparent, great-grandparent, and so on of a LabVIEW class. LabVIEW Object is the ultimate ancestor of all LabVIEW classes.
  • Descendant class—LabVIEW class that is the child, grandchild, great-grandchild, and so on of a LabVIEW class.

Wire Appearance

Classes define new data types. Wires of those class types appear on the block diagram as the default LabVIEW class wire or inherit the wire appearance of the parent class. You can change the wire appearance of a LabVIEW class in the Class Properties dialog box. To create a block diagram that is easy to read, you can change the wire appearance of different LabVIEW classes when appropriate. Having excessive wire colors and patterns can make the block diagram more difficult to read. The following image demonstrates the LabVIEW built-in wire appearances on the left and some possibilities for custom wire appearances on the right.

Refer to the LabVIEW Style Checklist for more information about guidelines for changing wire appearance.

Dynamic and Static Dispatch Member VIs

A method is an operation a LabVIEW class defines. In LabVIEW object-oriented programming, methods are member VIs you create. The member VIs perform an operation on the data of the LabVIEW class. You can define some methods with a single VI. These are called static dispatch methods because LabVIEW calls the same VI every time. You also can define methods by multiple VIs with the same name throughout the class hierarchy. These are called dynamic dispatch methods because exactly which one of the set of VIs LabVIEW calls is not known until run time. Dynamic dispatch methods are similar to polymorphic VIs. Where polymorphic VIs determine which VI to call depending on the data type you wire to it, dynamic dispatch methods wait until run time to determine which member VI in the class hierarchy to call depending on the data that arrives at the input terminal.

You designate a member VI as either static or dynamic in the connector pane of the member VI. If the connector pane includes a dynamic dispatch input terminal, the member VI is part of a dynamic dispatch method. If there is no dynamic dispatch input terminal, the member VI defines a static dispatch method.

When one LabVIEW class inherits from another LabVIEW class, the child class inherits all the public and protected methods defined on the parent class. By naming a member VI in a child class exactly the same name as a member VI in the parent class, you define the child implementation of the method.

Because LabVIEW defines static dispatch methods by a single VI, do not name a child class member VI with the same name as a static dispatch member VI in the ancestor class. For example, if parent class Automobile includes a static dispatch member VI, Open Door VI, then child class Truck cannot have a member VI named Open Door VI. The method Open Door VI is already defined on Truck because Truck inherits the member VI from Automobile. If you place static dispatch member VIs on the block diagram as a subVI they behave in all ways as a normal subVI call.

You can define multiple dynamic dispatch member VIs for a method, one at each level of an inheritance hierarchy. If a dynamic dispatch member VI is defined in the parent class, and you also define it in the child class, the child class implementation overrides, or extends, the parent implementation. In the following example, class Automobile and class Truck both define an implementation of the dynamic dispatch method Set Make VI. If you place a dynamic dispatch member VI on the block diagram as a subVI, the node on the block diagram behaves just like a regular subVI call when LabVIEW is in edit mode. If you run the VI however, the data that comes into the dynamic dispatch input terminal determines which implementation of the dynamic member VI in the class hierarchy LabVIEW calls. Because a LabVIEW class wire can carry data of its own type or data of any child type, the node executes whichever implementation of the dynamic dispatch member VI you define for the class data. Examine the following example again. Only the class Automobile implementation of Set Make VI is on the block diagram of Main VI. In the first iteration of the loop, LabVIEW executes the class Automobile implementation of Set Make VI because the data for class Automobile is on the class wire. In the second iteration of the loop, LabVIEW executes the class Truck implementation of the Set Make VI because the data for class Truck is on the class wire.

Note  LLBs cannot contain files of the same name. Therefore, if you have dynamic member VIs that share names in a class hierarchy, you cannot put these classes in the same LLB.

Note  If you define multiple dynamic member VIs for the same method at different levels in the class hierarchy, all VIs of the method must have the same reentrant settings, preferred execution settings, priority settings, connector pane terminal, connector pane pattern, and access scope.

Double-click a dynamic dispatch subVI that is on the block diagram to display the Choose Implementation dialog box. You can use this dialog box to view all implementations of a dynamic dispatch subVI that are currently in memory and then open one or more implementations of the subVI.

If you create a VI to override an ancestor implementation of a dynamic dispatch member VI by selecting New»VI for Override, you create another dynamic dispatch member VI, because VIs that override an ancestor member VI have the same name as the ancestor and also include dynamic dispatch terminals. LabVIEW places a Call Parent Method node on the block diagram with the appropriate dynamic dispatch input and output class terminals and other terminals the VI needs to match the ancestor VI. LabVIEW disables the VI for Override option if no ancestor member VI exists to override.

Use dynamic dispatch member VIs in a LabVIEW class to take advantage of recursion. Recursive VIs can call themselves on their own block diagram including on the block diagram of any subVIs. Recursion is useful if you want to operate many times on the output of the same process. You can configure a member VI to allow recursion.

Dynamic Dispatch Outputs

You can mark a LabVIEW class output terminal as dynamic by right-clicking the output terminal in the connector pane and selecting Dynamic Dispatch Output (Recommended). When you call a VI with a dynamic dispatch output terminal as a subVI the dynamic dispatch output changes to the same data type as the wire connected to the dynamic dispatch input terminal. For example, if you connect a wire of class Automobile to a dynamic dispatch input terminal, the output of the member VI is the same as the input; in this case the output is class Automobile. You can modify the data between the dynamic dispatch input terminal and the dynamic dispatch output terminal. However, to ensure the run-time safety of LabVIEW classes, the data from the dynamic dispatch input terminal must flow to all dynamic dispatch output terminals. Also, to ensure that LabVIEW reads from a dynamic dispatch input terminal exactly once and writes to a dynamic dispatch output terminal exactly once, you cannot place dynamic dispatch front panel terminals inside a structure.

Note  If you are debugging a dynamic dispatch member VI with dynamic dispatch inputs and dynamic dispatch outputs, you can examine the wire that flows from the dynamic dispatch input to the dynamic dispatch output for errors. The background color of the wire is gray instead of the usual white for any wire that originates at a dynamic input and does not pass through any functions that can change the run-time data type. The background color of the wire turns red if the wire passes through a function that can change the data type. In order for the dynamic outputs to work correctly, you cannot change the data type of a LabVIEW class.

If you want to complete an operation on the block diagram of a member VI that you know results in a LabVIEW class output data type that is different than the input, make sure the LabVIEW class dynamic output terminal on the connector pane is set to Recommended instead of Dynamic Dispatch Output (Recommended). For example, if the LabVIEW class input is Automobile and you know that you want to output the LabVIEW class Truck, you should change the LabVIEW class default terminal on the connector pane. Alternatively, you can create the member VI using a blank VI, which allows you to manually set the connector pane terminals.

Note  If you use a Case or Event structure in a member VI with dynamic dispatch inputs and dynamic dispatch outputs, you must manually wire the tunnel in all cases of the structure. If you use Use Default if Unwired on the output tunnel, LabVIEW breaks the VI.

Refer to the following projects for examples using dynamic dispatch terminals.

  • labview\examples\lvoop\DynamicDispatching\Dynamic Dispatching.lvproj 
  • labview\examples\lvoop\DynamicTerminals\Dynamic Terminals.lvproj 

Resources


 

Your Feedback! poor Poor  |  Excellent excellent   Yes No
 Document Quality? 
 Answered Your Question? 
Add Comments 1 2 3 4 5 submit