Working with external sources
Introduction
When implementing applications, you often need to refer to external sources, such as large external libraries, without explicitly representing them at model level or by type libraries. For example, you may want to re-use external code or plug your applications to an external environment by implementing/overriding external interfaces.
Objecteering C++ Developer provides features that let you conveniently use external sources in application UML models.
Using external headers
You can specify the external headers to use in a model class in the "Externals" tab of the C++ edition dialog box for a class (Figure 37).

Figure 37. Specifying external headers in the "Externals" tab of the C++ edition dialog box on a class
Objecteering C++ Developer injects the text entered in the "Header includes and using namespaces" field into the header file of the selected class, right after automatically generated include directives. Similarly, the text entered in the "Body includes & using namespaces" field is injected into the body (C++ source) file of the selected class, also after automatically generated include directives. Arbitrary C++ constructions are possible in those fields.
For example, let's imagine that we want to use our custom logging service in the "TaskWindow" class. We do not want to represent the "MyLogger" class, which implements the service, at model level, because it is not relevant to our application, so instead we write the code in the "Body includes & using namespaces" field of the "TaskWindow" class edition box. We want our code to be injected into the body file to isolate usage of the logging service from other application parts. For this, we are going to enter our code in the "Body includes and using namespaces" field (Figure 38).

Figure 38. Entering our code in the "Body includes and using namespaces" field
The code entered in this text field is injected into the body file of the "TaskWindow" class.
#include "MyPlanner/GUI/Windows/TaskWindow.h"
//modifiable zone
@13927@30671900:980@T
#include
"MyLog/MyLogger.hpp"
#ifdef DEBUG
#define MY_LOGGING_LEVEL 9
#endif
using namespace MyLogger;
//modifiable zone
@13927@30671900:980@E
namespace MyPlanner
{
namespace GUI
{
namespace
Windows
{
TaskWindow::TaskWindow()
{
//modifiable zone @13351@30671900:701@T
//modifiable zone @13351@30671900:701@E
}
TaskWindow::TaskWindow(const
TaskWindow& value)
{
//modifiable zone @13363@30671900:713@T
//TODO: write copy constructor code
//modifiable zone @13363@30671900:713@E
}
TaskWindow&
TaskWindow::operator =(const TaskWindow& value)
{
//modifiable zone @13381@30671900:731@T
//TODO: write assignment operator
code
//modifiable zone @13381@30671900:731@E
//modifiable zone @13382@30671900:732@T
return *this;
//modifiable zone @13382@30671900:732@E
}
TaskWindow::~TaskWindow()
{
//modifiable zone @13388@30671900:738@T
//TODO: write destructor code
//modifiable zone @13388@30671900:738@E
}
void
TaskWindow::formatDisplayTitle(std::string FormatStr)
{
//modifiable zone @13845@30671900:918@T
//modifiable zone @13845@30671900:918@E
}
}
}
}
Note: The "Externals" tab page is available only in the class C++ edition dialog box. To use external sources required for model operations or structural features, these must be specified for the owner classes.
Inheriting external classes
You can specify a selected class to be inherited from an external non-modeled class in the "Externals" tab of the class C++ edition dialog box (Figure 39).

Figure 39. Specifying a selected class to be inherited
Objecteering C++ Developer injects the text entered in the "External inheritance" field after the colon token in the selected class definition, thus producing the inheritance declaration. To include headers with the definition(s) of the specified external class(es), the "Header includes & using namespaces" field can be used.
We want the "TaskWindow" class to be a child of the "CWnd" class from the MFC library, which represents a window and provides services for windows management. It is not wise to define this class in the "MFC" type library, because inheritance from a datatype (which would represent the "CWnd" class on the model) does not seem semantically correct.
Therefore, we enter public inheritance declaration and include the external headers with the "CWnd" definition in the respective fields of the "TaskWindow" class C++ edition dialog box.

Figure 40. Entering public inheritance declaration and including external headers
Objecteering C++ Developer produces the following code for the "TaskWindow" class. External inheritance declaration and headers are injected. By clicking the "Preview" button in the class C++ edition dialog box, we can obtain this code immediately.
//includes for used library types
#include <string>
#include <cstringt.h>
#include
<afxwin.h>
#include <afxcoll.h>
//automatic includes (friends, associated classes, etc)
#include "MyPlanner/GUI/ITaskView.h"
#include "MyPlanner/TaskManagement/Task.h"
//modifiable zone @13936@30671900:989@T
#include "afxwin.h"
//modifiable zone @13936@30671900:989@E
namespace MyPlanner
{
namespace GUI
{
namespace Windows
{
class TaskWindow : public CWnd, public
GUI::ITaskView
{
//...
private:
CString
displayTitle;
public:
CDC
dc;
//associations
public:
TaskManagement::Task*
task;
CMap<CString,CString&,CBrush,CBrush&>
brushResource;
//operations
public:
TaskWindow();
TaskWindow(const TaskWindow& value);
TaskWindow&
operator =(const
TaskWindow& value);
~TaskWindow();
void formatDisplayTitle(std::string
FormatStr);
//non-modeled
members
};
}
}
}
Representing external classes
To explicitly represent relations with external classes, it can be useful to include them in the model. These classes may have quite a complex structure, which сan make them difficult to reverse or irrelevant to the modeling context.
To represent an external class in the model without specifying its full structure, you can set the "External code" flag in the class C++ edition dialog box. You then specify the code required to use the external class (include directives, macro commands) in the "External headers for external code" field. Instead of translating the modeled class structure, Objecteering C++ Developer simply injects the code specified in the field into the class header file.

Figure 41. Setting the "External code" flag and specifying the code required to use the external class
As a result, you can specify only the relevant parts of external classes. These parts do not need to be specified to exactly correspond to the external class sources.
For example, we want to explicitly model the fact that the "TaskWindow" class is the child of the "CWnd" class from the MFC library. We create the "CWnd" class in the model and create UML operations to explicitly represent certain message handlers that we want to override. We do not define exact message handler signatures, but rather simply show their names in the model (Figure 42).

Figure 42. The newly created "CWnd" class with its operations
To specify the "CWnd" class as being external, we set the "External code" flag and provide the headers required to use the "CWnd" class from the MFC library in the class C++ edition dialog box (Figure 43).

Figure 43. Specifying that the "CWnd" class is external
Objecteering C++ Developer produces only the following code for the "CWnd" class (despite the fact that the "OnCreate" and "OnPaint" UML operations are presented in the model).
#ifndef
__CWnd_15265_H_INCLUDED
#define
__CWnd_15265_H_INCLUDED
/*
* File type: Class header
* Class: CWnd
*/
#include "stdafx.h"
#include "afxwin.h"
#endif
__CWnd_15265_H_INCLUDED
This header is included when the "CWnd" class is used, so the "CWnd" class external definition (provided in the "afxwin.h" file) is available to all the class clients. For example, the "CWnd" class external definition is available in the code generated for the "TaskWindow" class.
//includes for used library types
#include <afxtempl.h>
#include <cstringt.h>
#include <afxwin.h>
#include <afxcoll.h>
//automatic includes (friends, associated classes, etc)
#include "MyPlanner/GUI/Windows/CWnd.h"
#include "MyPlanner/GUI/ITaskView.h"
#include "MyPlanner/TaskManagement/Task.h"
namespace MyPlanner
{
namespace GUI
{
namespace Windows
{
class TaskWindow : public CWnd, public
GUI::ITaskView
{
//...
private:
CString
displayTitle;
public:
CDC
dc;
//associations
public:
TaskManagement::Task*
task;
CMap<CString,CString&,CBrush,CBrush&>
brushResource;
//operations
public:
TaskWindow();
TaskWindow(const TaskWindow& value);
TaskWindow&
operator =(const
TaskWindow& value);
~TaskWindow();
void formatDisplayTitle(std::string&
FormatStr);
CDC
getDc();
//non-modeled
members
};
}
}
}
Overriding external functions
To interface the application with an external environment, it can be necessary to override certain virtual functions defined in external sources. It is often necessary to override message handlers defined in the external GUI library, such as MFC.
To override an external virtual function, carry out the following steps:
1. Import its declaration into the model using one of the methods described above (by using external headers, by inheriting from an external class or by specifying a relationship with an external class represented in the model).
2. Create a UML operation with the same name and signature in the model.
3. Specify parameter types to exactly match external function parameters and operation specifiers to exactly match the function declaration.
To match the parameter type with an external one, you should simply switch off the automatic decoration flag in the C++ edition dialog box for the parameter, before specifying the intended type specifiers in the same dialog box.
Note: If you change the deduced values of the "Pointer type", "Container type" and "Collection pointer type" properties in the parameter edition dialog boxes, the automatic decoration flag is switched off by Objecteering C++ Developer.
For example, in the "TaskWindow" class we want to override the "OnCreate" message handler defined in the "CWnd" parent external class.
The "OnCreate" message handler has the following declaration:
class CWnd : public CCmdTarget
{
//...
public:
afx_msg int OnCreate(CREATESTRUCT* lpCreateStruct);
//...
};
We create the "OnCreate" operation in the "TaskWindow" class, and then set its "lpCreateStruct" parameter to the "CREATESTRUCT" dummy datatype (this structure is defined in the "afxwin.h" header, so it is available as a result of inheritance from the external "CWnd" class).

Figure44. The "OnCreate" operation in the "TaskWindow" class with its "lpCreateStruct" parameter
Automatic
deduction comes up with the following C++ decorations of the "lpCreateStruct"
parameter (Figure 45).

Figure 45. Automatic deduction of C++ decorations for the "lpCreateStruct" parameter
As a result, Objecteering C++ Developer produces code where the "OnCreate" operation does not, in fact, override the external message handler, because its declaration is different.
namespace MyPlanner
{
namespace GUI
{
namespace Windows
{
class TaskWindow : public CWnd, public
GUI::ITaskView
{
//...
public:
//...
int OnCreate(const CREATESTRUCT& lpCreateStruct);
};
}
}
}
To correct this, we manually specify the C++ properties of the "lpCreateStruct" parameter (Figure 46). We specify its type as the pointer, and remove the const specifier.

Figure 46. Manually specifying the C++ properties of the "lpCreateStruct" parameter
As a result, Objecteering C++ Developer switches off the automatic decoration flag for the "lpCreateStruct" parameter and instructs that automatic deduction for this model element should be skipped and that only C++ decorations specified by us should be used.

Figure 47. The automatic decoration flag has been switched off
The last remaining action is to define the "afx_msg" specifier for the "OnCreate" operation. This specifier is set in the operation C++ edition dialog box (Figure 48).

Figure 48. Defining the "afx_msg" specifier for the "OnCreate" operation
As a result, Objecteering C++ Developer produces the correct code for the "TaskWindow" class, where the "OnCreate" function does override the "OnCreate" message handler defined in the external "CWnd" class.
//includes for used library types
#include <cstringt.h>
#include <afxwin.h>
#include <afxcoll.h>
//automatic includes (friends, associated classes, etc)
#include "MyPlanner/GUI/Windows/CWnd.h"
#include "MyPlanner/GUI/ITaskView.h"
#include "MyPlanner/TaskManagement/Task.h"
namespace MyPlanner
{
namespace GUI
{
namespace Windows
{
class TaskWindow : public CWnd, public
GUI::ITaskView
{
//...
private:
CString
displayTitle;
public:
CDC
dc;
//associations
public:
TaskManagement::Task*
task;
CMap<CString,CString&,CBrush,CBrush&>
brushResource;
//operations
public:
TaskWindow();
TaskWindow(const TaskWindow& value);
TaskWindow&
operator =(const
TaskWindow& value);
~TaskWindow();
void formatDisplayTitle(std::string&
FormatStr);
CDC
getDc();
afx_msg int OnCreate(CREATESTRUCT* lpCreateStruct);
//non-modeled
members
};
}
}
}