【发布时间】:2010-11-14 03:09:14
【问题描述】:
假设我正在开发一个适用于 Item 类型项目的库。主要入口点是这样的类:
class Worker
{
private:
SomeContainer _c;
public:
void add( const Item &i );
void doSomething();
};
doSomething() 方法查看添加的项目,比较它们等,并对它们进行处理。所以 Item 类需要一个operator==。
现在,我想在不同的环境中使用这个库,并且在每个环境中,Item 类的实现都是不同的。因此,Item 需要一个虚拟比较函数:
class Item
{
protected:
virtual bool _equals( Item &other ) = 0;
public:
bool operator==( Item &other ) { return _equals( other ); };
};
每个环境都有自己的 Item 实现。该库只知道 Item 类,并且使用该库在特定于平台的应用程序中定义和实现特定的 item 类。在环境 A 中可能是:
class AItem: public Item
{
private:
bool _equals( Item &other );
std::string _member;
...
};
在环境 B 中:
class BItem: public Item
{
private:
bool _equals( Item &other );
int _member;
...
};
现在,对于每种环境,实现库使用的比较的最佳方法是什么? _equals是在Item类中指定的,所以其具体的item实现需要将other转换为自己的类型。
在给定的环境中,不会同时使用不同的项目类型,因此假设,以下是安全的:
bool AItem::_equals( Item &other )
{
return this->_member == static_cast<AItem &>(other)._member;
}
但这似乎是一个令人讨厌的解决方案,因为它允许使用该库的程序员实现一个新环境,如果他将不同类型的项目添加到 worker 中来破坏事物。
我能想到的其他解决方案是:
- 使用
dynamic_cast。 - 通过将成员添加到指示环境的基本 Item 类来实现我自己的 RTTI 排序。然后可以在比较函数中使用它来查看
other是否属于同一类型。不是很优雅。 - 实现库中的所有类型,并在编译时根据
#define选择正确的类型。这意味着库本身必须针对每个环境进行扩展。 - 使用模板化工作器。
但我觉得必须有一个更优雅的解决方案。也许是完全不同的东西。你会怎么做?
【问题讨论】:
-
您的最后一个选项“使用模板化工作者”将是最好和最优雅的解决方案。它还具有性能最佳的优势,因为它在比较时避免了虚拟调用。
-
与您的问题无关,但您确实不应该使用以下划线开头的名称。少数合法案件的规则非常复杂。前导下划线后跟大写字母或双前导下划线始终由实现保留。前导下划线后跟小写在全局命名空间中保留(因此在技术上是合法的,但养成不使用前导下划线的习惯会省去很多麻烦)
-
这是一个非常相关的问题:似乎只有少数人意识到平等并不那么简单。
标签: c++ api inheritance casting