Open C++ methods throw an exception whenever an error occurs, which alleviates you from having to check an error code returned from each method called. You manage these exceptions using try blocks and catch blocks, which enable you to recover, resume, or re-throw the exception whenever one occurs.
The vector math package (vmathpp) throws an exception object that derives from VectorMathException whenever a math error occurs. For example, constructing a Matrix3 object can cause either a VectorMathZeroVector or VectorMathNonOrthogonal exception object to be thrown. You can match vmathpp errors to the class of the exception object thrown:
Vector3 x_vector, y_vector;
// Initialize x_vector and y_vector
??? Matrix3 matrix3 ( Matrix3::XY_Input, x_vector3, y_vector3 );
catch ( VectorMathZeroVector & )
??? cout << "Un-initialized or zero vector" << endl;
catch ( VectorMathNonOrthogonal & )
??? cout << "Vectors are non orthogonal" << endl;
catch ( VectorMathException & )
??? cout << "Caught an unexpected vmathpp exception" << endl;
The main Open C++ library (openpp) throws a UgException object whenever an error occurs. For example, attempting to add an attribute that already exists causes a UgException object to be thrown. You can match openpp errors to the class of exception object throw:
std::string title ( "AttributeName" );
int int_value = 0;
??? typed_object->addIntAttribute ( title, int_value );
catch ( UgException &exception )
??? // Check the error code of the exception against a known
??? // error code defined in uf_modl_error.h
??? if (ATTRIBUTE_ALREADY_EXISTS == exception.getErrorCode ( ) )
??? cout << "Attribute already exists" << endl;
??????? cout << "Caught unexpected NX error:" << endl;
??????? cout << exception.getErrorText ( ) << endl;
catch ( VectorMathException & )
??? cout << "Caught an unexpected vmath exception" << endl;
Note that NX does not catch any C++ exceptions at all. It is incumbent on the client to catch and properly handle all exceptions. In the future, NX may be capable of catching Open C++ exceptions. As a minimum, you should wrap all Open C++ applications with a last chance try and catch block.
You can decide what granularity of error checking is best for your situation. You can wrapper individual Open C++ calls with try and catch blocks as in the above examples, or you can catch errors at a fairly high level in your application. Normally, you will use some combination of both techniques.
You should not use ufusr_ask_unload() function with Open C++ applications since Open C++ logs callbacks with Open C for the management of tags and UDOs. Using this function can cause unpredictable results.
A Open C++ object that represents an object that resides in an NX part file is always returned "by-reference" ? that is, via a pointer to the object, such as a pointer to a UgLine object. All other objects are returned "by-value" unless the dynamic_cast operator is needed. For example, a Curve object is returned via a pointer so that you can invoke dynamic_cast on it in order to convert it to a pointer to a Line object.
A Open C++ object exists for a given NX object, but not until it is needed by Open C++. In general, a Open C++ object is bound to an NX object whenever its pointer is returned via a create or inquire method. If a Open C++ object exists then it is unique to a particular NX object. That is, there is at most one Open C++ object for any given NX object.
Open C++ manages by-reference objects while by-value objects are deleted whenever they go out of scope. You should never invoke the delete operator on a by-reference object. If you want to delete the NX object, you should invoke UgInPartObject::destroy() instead. This method removes the object from the part file so that it is no longer accessible by the user or by your application. However, it does not delete the corresponding Open C++ object immediately. Instead, it sets it to the "null state". Similarly, if the user interactively deletes an NX object, the corresponding Open C++ object (if there is one) is set to the null state. The Open C++ object is not deleted when the corresponding NX object is deleted because the NX object might "come back to life" via an Undo.
A Open C++ object is actually deleted only whenever it is impossible for the corresponding NX object to be recovered. For example, closing the part deletes all the Open C++ objects associated with that part.
Even though the pointer to your Open C++ object is still valid after deleting its NX object, you cannot do much with it. If you try to do any inquiries on it, you will generate an exception.
// Initialize the pLine pointer
// The following method will remove the line from the part file
// but pLine is still a valid pointer.
// Although the pLine pointer is still valid, it refers to an
// object that is in the "null state" so the following line
// will cause an exception to be thrown
std::string name = pLine->getName ();
A Open C++ object that is in the null state can be re-associated to its original NX object. This happens whenever you undo to a state prior to when the NX object was deleted. (This is the main reason for retaining the Open C++ object whenever its NX object is deleted. Otherwise, you would have lost the reference with no way of getting it back after the undo).
Persistent data in Open C++ extended objects are affected by undo. There is no mechanism for any transient data that may be a part of a Open C++ extended object. Note we do not recommend using the UgExtensionObject anymore - the Common API (as of NX5) has a better solution for UDO's.
As a general rule, a Open C++ object will never be deleted if it can be recovered via undo. However, a Open C++ object will be deleted if you undo to a state that is prior to its creation, or if there are no reachable undo marks prior to its deletion.
Upcasting is always safe but downcasting is not.
// If pLine is a valid pointer, the following upcast works
// No explicit upcasting is required in C++
pTyped = pLine;
// The following downcast is unsafe, even if pTyped is a
// valid pointer because it may not be a pointer to a UgLine
pLine = (UgLine *) pTyped;
When downcasting you should use the C++ dynamic_cast operator. This function returns a pointer to the desired object if the downcast can be performed; otherwise, it returns 0. In this way you can move down a series of classes in the class hierarchy. For example, you can determine if a UgEvaluatableObject object is linear or not in the following fashion:
Curve *pCurve = pEvalObj->askCurve ( );
if ( dynamic_cast < Line * > ( pCurve ) )
??? cout << "A linear evaluatable object" << endl;
??? cout << "A non linear evaluatable object" << endl;
Downcasting is also useful when iterating through UgTypedObject objects.
UgPart *pWorkPart = UgSession::getWorkPart();
for (pCurObj = pWorkPart->iterateFirst();
pCurObj = pWorkPart->iterateNext (pCurObj))
??? UgArc *pUgArc = dynamic_cast <UgArc *> pCurObj;
??? if ( pUgArc )
??????? double radius = pUgArc->getRadius();
??????? cout << "This is not an arc" << endl;
Open C++ applications share the same license as traditional Open C applications. If your application makes use of both Open C++ and traditional Open C functions, it will check out a single license. The license is checked out when Open C is initialized in any of the following ways:
Create a UgSession object specifying true in the constructor
The license is normally checked back in when Open C is terminated, which can occur in the following ways:
A UgSession object that was created by specifying true in the constructor goes out of scope
It is important to note that once an external Open C application has checked in a license, it cannot be checked out again.