Question-and-Answer Resource for the Building Energy Modeling Community
Get started with the Help page

# OpenStudio SDK: when should the _Impl header files be included?

I know this is a bit outside the scope of UnmetHours, but I still don't see a better place to post this question, and I cannot find the answer in the wiki/documentation/developper documentation of OpenStudio.

As far as I understand OpenStudio uses the  Pointer to Implemention (PIMPL, or Cheshire Cat idiom) for a variety of reasons including having a more stable API, hidding the implementation from the public eye, and - what's of interest to me here - reducing recompilation time.

In OpenStudio, the current coding standard is to have one class.hpp header file for the public side, and class_Impl.hpp for the private side. Both are implemented in the same class.cpp source file, and the public class only forwards to the Impl one.

To use an example: let's consider the class ThermalZone and the class Space. Let's assume that Space only has a single method called setThermalZone() that returns a std::vector<Space> of all spaces.

Space.cpp:

#include "Space.hpp"
#include "Space_Impl.hpp"

#include "ThermalZone.hpp"
// THIS? #include "ThermalZone_Impl.hpp"

// Impl method  (declared in Space_Impl.hpp), that actually does the work
bool Space_Impl::setThermalZone(ThermalZone& thermalZone)
{
bool result = this->setPointer(OS_SpaceFields::ThermalZoneName, thermalZone.handle());
if (result){
thermalZone.checkDaylightingControlsAndIlluminanceMaps();
}
return result;
}

// Public method (declared in Space.hpp), that simply forwards
bool Space::setThermalZone(ThermalZone& thermalZone)
{
return getImpl<detail::Space_Impl>()->setThermalZone(thermalZone);
}


If I'm following correctly, the gain in recompilation time arises if I modify the implementation of ThermalZone (ThermalZone_Impl), Space doesn't have to be recompiled because it's linking only to the ThermalZone.hpp header file.

The thing is, I very often see both the class.hpp and class_Impl.hpp being included in various classes (see the actual Space.cpp#L49 where ThermalZone_Impl.hpp is indeed included), when I don't see any of the class_Impl methods being used anywhere.

So my question is: when must/should I include the class.hpp? And more importantly, when must/should I also include the class_Impl.hpp?

edit retag close merge delete

Sort by » oldest newest most voted

First of all, nothing in this question applies to the Ruby API so if you are only writing measures you can stop reading this question now :-) This is only of interest to people developing the C++ portions of OpenStudio.

OpenStudio does use the PIMPL idiom for all of the ModelObject classes. There are many advantages to PIMPL but OpenStudio does not make use of many of them. PIMPL was chosen for OpenStudio mainly for properties of the SWIG wrappers, it was the best way to get ModelObjects that "acted right" in Ruby. Each ModelObject has three C++ source files associated with it:

• FooObject.hpp - the public header
• FooObject_Impl.hpp - the private header
• FooObject.cpp - implementation of the public and private classes

The Cpp file implementing FooObject and FooObject_Impl needs to include both headers.

Another file that simply uses FooObject can get away with only including FooObject.hpp. However, any code that needs to cast a ModelObject to a FooObject needs to include both FooObject.hpp and FooObject_Impl.hpp.

This casting ends up being fairly pervasive, e.g. model.getModelObjects<FooObject>(), so the Impl headers are included in more files than I would like. We could work around this by adding explicit cast methods for each type like those generated in Ruby, e.g. model.getFooObjects(), but we have not bitten that off.

more