The following provides a high level overview and explains the rationale behind many of the design decisions made for Open C++. The coding standards are also summarized.
The Open C++ header files were designed to hide as much of the implementation details as possible. This helps to ensure that the client designs programs based on what a class does rather than how it does it. For example, you should ignore the private section of a class along with its friends and the implementation details of macros and templates. You may reference the protected section of a class, but only in a derived class. The public section is the portion of the class that is for all to use. DO NOT MODIFY MACROS OR TEMPLATES.
In general, each header file declares a single class along with its helper classes. This single class is used to name the header file. For example, UgLine is declared in ug_line.hxx while UgSpline and its helper class ThruPoint are declared in ug_spline.hxx.
The Open C++ headers have an extension of hxx. Header files that begin with "ug_" contain definitions for NX objects and concepts while those that do not model generic objects/concepts. For example, ug_line.hxx models a Open C line while line.hxx models a mathematical line.
The nesting of the Open C++ header files is kept to a minimum to limit compile time dependencies. For example, Point3 is declared as an incomplete class within ug_line.hxx rather than including point3.hxx. This means that the client must include both ug_line.hxx and point3.hxx in order to invoke UgLine::getStartPoint ().
The Open C++ classes that begin with "Ug" represent NX objects and concepts while those that do not represent generic objects and concepts. For example, UgLine represents a NX line while Line represents a mathematical line. Classes that end in "Object" are base classes, from which the "Ug" instantiable classes are derived. For example, the "Ug" instantiable class UgLine inherits from the base class UgCurveObject.
Open C++ classes are normally not nested within other classes in order to simplify the design. For example, in ug_face.hxx, Loop is declared outside of UgFace even though it is a UgFace helper class.
Prior to V18, there were three template classes in Open C++. UgArray and UgString were partial wrappers around the STL classes std::vector and std::string, respectively. UgIterator is the third template class. UgIterator can be used to iterate over objects in a part file, or used to iterate over all open parts in the current session. In V18, the STL classes std::vector and std::string replaced and obsoleted UgArray and UgString, respectively. UgIterator still exists in V18. Do not rely on the implementation of a template class, and NEVER MODIFY A TEMPLATE.
By definition, C++ objects are statically defined. For this reason any dynamic behavior that is not under direct user control is not modeled as a `Ug' class. For example, there is no UgLinearEdge class in Open C++. This is because an edge can change form as a side effect of an edit operation, and as a result a UgLinearEdge object may no longer be linear after an edit. For this reason, only UgEdge objects are modeled.
These dynamic behaviors are modeled via methods and helper classes. For example, you can get the curve data of an edge by invoking UgEvaluatableObject::askCurve ( ), and from the returned Curve object you can determine if the edge is linear or not. It is important to remember though that the Curve object returned is simply a snapshot of the UgEdge object at a point in time; if the UgEdge object changes form as the model updates, that change is not reflected in any Curve object that was acquired before the change.
Multiple inheritance is used to `mixin' functionality that is not limited to a single branch of the class hierarchy. For example, all typed objects are attributable (that is, may contain attributes) but not all attributable objects are typed. Thus, both UgTypedObject and UgPart must `mixin' UgAttributableObject. Multiple inheritance guarantees that the attribute interface remains consistent across the class hierarchy. Multiple inheritance is used only where absolutely necessary.
Multiple inheritance is used extensively to unify access to curves and edges.
Each class publishes its interface via methods. The following explains how methods are defined within Open C++.
Methods that return a Boolean value begin with "is". For example,
bool is_solid = body->isSolid ( );
Methods that return data begin with either "ask" or "get". For example,
int type = typed_object->askType ( );
const std::string name = typed_object->getName();
Methods that edit data begin with "set". The "get" methods have a corresponding "set" method, whereas the "ask" methods do not. For example, you cannot "set" the type of a object but you can "set" its name:
typed_object->setName ("Hello world");
A method that returns a single result does so via a return value. If an object is returned by such a method, it is returned as either a const object or as a pointer to the object. A method that returns multiple results does so via output parameters that are passed as pointers to the method.
Input parameters are passed either by value, as const references, or as pointers to "Ug" class objects. Input parameters are always listed prior to the output parameters.
Default parameters are only used as a convenience for the client code; they are not used to change the semantic of the method. For example, the tolerance parameter in UgEvaluatableObject::computeIntersectionPoints ( ) defaults to a standard tolerance that is adequate for most applications.
Overloading is sometimes used to provide more than one method with the same name, but with different semantics. For example, there are three UgExpression::create ( ) methods. All three create a UgExpression object, though each in a different way: one creates a UgExpression from a complete expression std::string object, another from a Left Hand Side (LHS) std::string object and a Right Hand Side (RHS) std::string object, and the third from a LHS std::string object and a RHS double value.
Operator overloading is only used where a clear mathematical interpretation exists. Otherwise, methods are used. This is why vmathpp classes use operator overloading much more than openpp classes.
Very few Open C++ methods are virtual since they are not to be overridden. You should not try to hide any Open C++ methods by implementing your own versions.
Most of the Open C++ virtual methods are not to be overridden by user-written code. For example, UgExpression and UgTypedObject override the virtual UgInPartObject::destroy ( ) method since each needs its own implementation. Virtual methods are often used to guarantee that the interface remains consistent across the class hierarchy.
The only Open C++ virtual methods that you can override are the UgExtensionObject methods infoObject ( ), memberDeletion ( ), and update ( ). The implementations for these methods should be provided by derived classes. Note we do not recommend using the UgExtensionObject anymore - the Common API (as of NX5) has a better solution for UDO's.
Methods are declared static whenever a this pointer is not necessary. For example, you may write to the info window without a UgInfoWindow object:
UgInfoWindow::write ( "Hello world" );
A this pointer is not needed because there is only one info window.
All create ( ) methods are static since the object does not exist yet. For example, you use the static UgPoint::create ( ) method to create an NX point object.
// Create a point at the origin and return its pointer
UgPoint *pUgPoint = UgPoint::create (Point3 ());