我可能会去做一些政策方面的事情:
template<typename Platform>
struct PlatDetails : private Platform {
std::string getDetails() const {
return std::string("MyAbstraction v1.0; ") + getName();
}
};
struct Windows {
std::string getName() const { return "Windows"; }
};
struct Linux {
std::string getName() const { return "Linux"; }
};
#ifdef WIN32
typedef PlatDetails<Windows> PlatformDetails;
#else
typedef PlatDetails<Linux> PlatformDetails;
#endif
int main() {
std::cout << PlatformDetails().getName() << "\n";
}
在这种情况下,使用CRTP进行常规的模拟动态绑定与此相比并没有太大区别。因此,通用的东西是基类,而具体的东西则是派生类:
template<typename Platform>
struct PlatDetails {
std::string getDetails() const {
return std::string("MyAbstraction v1.0; ") +
static_cast<Platform*>(this)->getName();
}
};
struct Windows : PlatDetails<Windows> {
std::string getName() const { return "Windows"; }
};
struct Linux : PlatDetails<Linux> {
std::string getName() const { return "Linux"; }
};
#ifdef WIN32
typedef Windows PlatformDetails;
#else
typedef Linux PlatformDetails;
#endif
int main() {
std::cout << PlatformDetails().getName() << "\n";
}
基本上在较新的版本中,getName必须是公共的(尽管我认为可以使用“friend”),继承也必须是公共的。而在旧版本中,继承可以是私有的和/或接口函数可以是受保护的(如果需要的话)。因此,适配器可以成为平台必须实现的接口与应用程序代码使用的接口之间的防火墙。此外,在旧版本中可以拥有多个策略(即同一平台无关类使用的多个平台相关facet),但对于新版本则不能。
与使用委托或非模板继承的版本相比,任何一种的优点都是你不需要任何虚函数。尽管最初接触策略设计和CRTP可能会让人感到害怕,但这些优点在实践中是具有可行性的。
但实际上,我同意quamrana的看法,通常您可以在不同的平台上拥有相同事物的不同实现。
#ifdef WIN32
#include "windows/platform.h"
#else
#include "linux/platform.h"
#endif
struct PlatformDetails {
std::string getDetails() const {
return std::string("MyAbstraction v1.0; ") +
porting::getName();
}
};
namespace porting {
std::string getName() { return "Windows"; }
}
namespace porting {
std::string getName() { return "Linux"; }
}