【发布时间】:2020-12-16 06:58:12
【问题描述】:
Scott Meyers 长期以来一直提倡使用非成员非友元函数而不是成员函数来改进封装。我可以看到这样做的好处。
但是,在我看来,一个缺点是:
我有一些自定义图像类的自定义元数据类,其中包含许多数据成员。有几种格式可以保存图像,并且必须将元数据转换为这些格式可以采用的格式(ENVI、png、TIFF...)。现在我按照 Scott 的建议将这些转换函数放入单独的命名空间中。它们本质上使用公共接口将所有成员复制到适合最终元数据格式的内容中,但它们需要包含所有数据成员。 示例:
// 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());
}
}
我看到的问题是,当其他人从事该项目并且该人将另一个数据成员添加到元数据时,他/她需要记住将此数据成员添加到所有转换函数中。由于它们位于不同的 header/cpp 文件中,因此很容易忘记这一点,并且我们有一个不明显的错误,即并非所有数据成员都保存在元数据中。如果函数是公共成员,查看头文件(在添加新数据成员时)可能会提醒该人也在其中添加成员,那么完成的必要性只在该文件中。
要点是,使用公共接口确实可以保证(如果接口没有改变),如果类中的某些内容发生变化,基于它的函数将继续工作,但如果向公共接口添加附加功能,则不能保证完整性类,也需要添加到这些函数中。
在某些情况下人们会建议不要遵循此建议吗?对于这种特定情况,是否有一些范式可以两全其美?
【问题讨论】:
-
Meyer 的建议的形式是“如果一个函数可以作为成员或非成员实现,那么更喜欢非朋友非成员”。这与“始终使用非朋友非会员”不同。
-
是的,这就是我隐含的意思。我的示例中的转换函数也可以是。