Scott Meyers has long advocated using non-member non-friend functions instead of member functions to improve encapsulation. I can see the advantages of this.
However, a disadvantage in my eyes is the following:
I have a custom metadata class for some custom image class, which contains a number of data members. There are a few formats in which the image can be saved and the metadata has to be converted into something those formats can take (ENVI, png, TIFF, ...). Now I followed Scott's advice and put these conversion functions into a seperate namespace. They essentially use the public interface to copy all members into something that fits the end metadata format, but they need to include all data members. Example:
// file Metadata.h
class Metadata
{
// Getters
std::string GetDescription() const;
std::string GetTimeStamp() const;
float GetExposureTimeInMilliSeconds() const;
// Setters
// ...
private:
std::string m_description;
std::string m_timeStamp;
float m_exposureTimeInMilliSeconds;
// Added later with associated getters/setters:
// std::string m_location;
// std::string m_nameOfPersonWhoTookThePicture;
};
// File UtilityFunctions.h
namespace UtilityFunctions
{
ENVIMetadata ConvertMetadataToENVIMetadata(const Metadata &i_metadata)\
{
ENVIMetadata envi;
envi.AddMetadata<string>("Description", GetDescription());
envi.AddMetadata<string>("Time stamp", GetTimeStamp());
envi.AddMetadata<float>("Exposure time", GetExposureTimeInMilliSeconds());
}
}
The problem I'm seeing is that when someone else would work on the project and that person would add another data member to the metadata, he/she needs to remember to add this data member to all the conversion functions. As they are located in a different header/cpp file, it is easy to forget this and we have a non-obvious bug that not all data members are saved in the metadata. If the function would be a public member, looking at the header file (while adding new data members) might remind that person to also add the members in there and then the necessity to be complete would only be in that file.
The takeaway is that using the public interface indeed guarantees (if the interface doesn't change) that functions based on it will keep working if something inside the class changes, but it does not guarantee completeness if additional features are added to the class, which need to be added to those functions as well.
Are there situations where one would advise not following this advice? Is there some paradigm for this specific situation to get the best of both worlds?