对于带有元素的类,可以替代联合

alternative to union for classes with ctors

本文关键字:于带 元素      更新时间:2023-10-16

我有一个关于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作为键,但我不想复制数据。显然我需要实现两个不同的比较函数。我的第一次尝试是这样做的:


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函数的指针,但在我看来,这似乎是一个不优雅的解决方案,并且可能相当混乱,以后很难调试。

在谷歌上搜索使用类联合的限制,我发现一个帖子建议解决一个类似的问题,使用转换操作符重载,但没有扩展太多。

我相信这是一个相当普遍的问题,有一个共同的设计解决方案,我只是不知道。

欢迎有任何想法或评论

代码中的实际问题是,您试图将比较数据结构和雇员数据结构放在同一个对象中。它们应该是不同的对象,像这样:

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;
};

比较器不是雇员——它不应该继承。创建单独的比较器,查看传递的Employee引用并对它们进行比较。

如果您不想复制数据,请使用例如boost::shared_ptr或以下方法:

list<Employee> ActualData;
map<int, list<Employee>::iterator> EmployeeByID;
map<float, list<Employee>::iterator> EmployeeBySalary; 

要查看:

map<int, shared_ptr<Employee> > EmployeeByID;
map<float, shared_ptr<Employee> > EmployeeBySalary; 

我怀疑除了在非常低级别的代码中有很好的联合用例。这几乎总是一个出价的想法,因为它可以招致许多不希望的效果(谷歌一点看到这一点)。

这里,您只想要一个树,其中键在一种情况下是ID,在另一种情况下是工资,并且项目是指向员工的指针

这样你就不会重复雇员,你只是有几个指向雇员的指针,这很好。这两棵树是分开的,这是理想的。(如果你想添加任何其他树,你可以做同样的事情,而不改变其他树的类型。)

如前所述,我还将使用多索引容器和某种智能指针指向员工对象。类似于(从我的头顶,未测试!):

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例二