我在C ++中有一个与设计相关的问题。
我正在为HW分配构建一棵树。 树实现非常简单。基本上它是一个模板化的类
template <typename TYPE, typename KEY>
class Tree
{
public:
void Insert(TYPE& node);
void Remove(TYPE& node);
TYPE& Find (KEY key);
//etc.
};
到目前为止只是背景。 现在,稍后当我使用Tree时,我有一个Employee类,我希望有2个树,但是一旦使用ID作为密钥,而另一个使用Salary作为密钥,但我不想复制数据。 显然我需要实现2个不同的比较函数。我的第一次尝试是做这样的事情:
class Employee
{
public:
int ID;
float Salary;
};
enum COMPARE_RESULT
{
LESS_THAN = -1,
EVEN = 0,
GREATER_THAN = 1
}
template
class IComparable
{
public:
virtual COMPARE_RESULT Compare (const T& other) const = 0;
};
class EmployeeCompareByID : public Employee, public IComparable
{
public:
Compare (const T& other) const
{
//Compare IDs and return result
}
};
class EmployeeCompareBySalary : public Employee, public IComparable
{
public:
Compare (const T& other) const
{
//Compare Salaries and return result
}
};
typedef union
{
Employee employeeData;
EmployeeCompareByID employeeCompareByID;
EmployeeCompareBySalary employeeCompareBySalary;
}EmployeeUnion;
//finally the main would do something like this:
int main()
{
//first tree key is by ID
Tree empTreeByID;
//second tree key is by salary
Tree empTreeBySalary;
EmployeeUnion emp;
emp.employeeData.ID = 1;
emp.employeeData.Salary = 1000.11;
empTreeByID.Insert(emp.employeeCompareByID);
empTreeBySalary.Insert(emp.employeeCompareBySlary);
//the same emp is referenced in both trees. Each by it's relevant member in union
}
但是这种方法失败了,因为我的Employee类有一个构造函数,复制构造函数和运算符重载,因此在Employee上定义一个联合是不可能的。 此外,这种方法要求Tree实现在TYPE上执行static_cast IComparable的模板参数对我来说很好。
另一个可能的解决方案是将一个函数指针传递给Tree构造函数,并指向该实例的相应Compare函数,但这似乎是一个不优雅的解决方案,可能非常混乱,以后很难调试。 / p>
通过Google搜索使用联盟与类的限制,我发现了一个帖子,建议使用转换运算符重载解决类似于我的问题,但没有扩展太多。
我确信这是一个相当常见的问题,有一个共同的设计解决方案,我只是不知道。
感谢任何想法或意见
答案 0 :(得分:2)
代码中的实际问题是您尝试将比较和员工数据结构放在同一个对象上。它们应该是这样的不同对象:
template<class T> class ICompare {
virtual bool Compare(const T &a, const T &b) const=0;
};
然后显然你需要修改Tree构造函数:
template<class T> class Tree {
Tree(const ICompare<T> &c) : c(c) { }
...
const ICompare<T> &c;
};
答案 1 :(得分:1)
比较器不是员工 - 它不应该继承。制作单独的比较器,查看传递的Employee
引用并进行比较。
如果您不想复制数据,请使用例如boost::shared_ptr
或此方法:
list<Employee> ActualData;
map<int, list<Employee>::iterator> EmployeeByID;
map<float, list<Employee>::iterator> EmployeeBySalary;
的shared_ptr:
map<int, shared_ptr<Employee> > EmployeeByID;
map<float, shared_ptr<Employee> > EmployeeBySalary;
答案 2 :(得分:1)
我怀疑除了非常低级代码之外,有一个很好的工会用例。它几乎总是一个出价的想法,因为它可以产生许多不受欢迎的影响(谷歌有点看到)。
在这里,您只想拥有一个树,其中一个是ID,另一个是工资,而该项是员工的指针。
这样你就不会重复员工,你只需要几个指向员工的指针,这很好。你的两棵树是分开的,这是可取的。 (如果你想添加任何其他树,你可以做同样的事情而不改变其他树类型。)
答案 3 :(得分:1)
如前所述,我还会使用多索引容器和某种指向employee对象的智能指针。 (从头顶开始,未经测试!):
typedef multi_index_container<
boost::shared_ptr < Employee >,
indexed_by<
// sort by unique id
ordered_unique < tag < EmployeeIdTag >, member < Employee,int,&Employee::m_id > >,
// sort by salary
ordered_non_unique < tag < EmplyeeSalaryTag >, member < Employee,int,&Employee::m_salary > >
>
> EmployeeContainer;
typedef EmployeeContainer::index<EmployeeIdTag>::type EmployeeContainerById;
typedef EmployeeContainer::index<EmplyeeSalaryTag>::type EmployeeContainerBySalary;
http://www.boost.org/doc/libs/1_46_1/libs/multi_index/doc/examples.html#example1