需要帮助理解C ++中的运算符重载

时间:2010-09-02 11:21:11

标签: c++ arrays operator-overloading

我正在尝试实现一个结构,它基本上是一个自定义的哈希表,其中包含任何内容(NULL)或指向二叉搜索树对象的指针。

无论如何,我无法弄清楚如何做一些事情,比如将哈希表(一个数组设置为NULL),以及将一个表中的BST对象记忆到另一个表中。

BST *prevData;
BST *currData;

据我了解,我认为我必须重载=和==运算符以允许将数组元素设置为NULL,这是正确的吗?我真的不清楚如何实现这一切,但是继续谷歌的例子,我得到了:

BST& BST :: operator= (int null);
bool BST :: operator== (int null);

==运算符重载是检查特定数组索引是否等于NULL。我假设我需要一些额外的代码,而不仅仅是原型,这就是我解开的地方。

第二点是memcpy,编译器不允许这样做。

memcpy(prevData[x], currData[x], sizeof(BST) * height);

抱怨

  

错误C2664:'memcpy':无法转换   参数1从'BST'到'void *'没有   用户定义转换运算符   可以执行此操作   转换,或运营商不能   称为

如果您需要更多信息,我很乐意为您填写。

任何线索?感谢。

2 个答案:

答案 0 :(得分:3)

  

据我了解,我想我必须这样做   将=和==运算符重载到   允许将数组元素设置为NULL,   这是对的吗?

不,一点也不。您已经描述了一组BST *指针,而不是BST个对象。 NULL已经是指针的有效值,您不需要更改任何C ++行为:

BST *array[LENGTH]; // LENGTH > 1
array[0] == NULL;
array[0] == new BST; // but watch for memory leaks!
array[1] == array[0];
array[0] == NULL; // now moved the array[0] pointer to array[1]

每当你有一个指针数组时,内存管理变得棘手,考虑shared_ptr等智能指针变得很重要。

编辑:正如评论中所讨论的,更好的解决方案是获得某种零BST值:

class BST {
    bool isNull_;
    BST() : isNull_(true) {}
    bool isNull() { return isNull_; }
    // rest of class definition...
};

现在,您有一个“空”BST值,bst.isNull_为真。默认值为空值。因此,如果您创建一个空矢量:

std::vector<BST> vec = std::vector<BST>(10);

这将初始化为10个空BST。 new[]数组分配运算符也是如此。

  

第二点是memcpy,我是   不被允许做的   编译器。

memcpy(prevData[x], currData[x], sizeof(BST) * height);

不要那样做!出于多种原因这是错误的,但主要是因为它是一个遗留的C函数,不适合C ++类;因为你要复制一个项目,而不是它们的一部分。

要复制一个项目,请使用operator=

currData[x] = prevData[x];

用于复制块数据的C ++函数是std::copy。使用它的一个原因是它可以识别重载的operator=赋值运算符,而memcpy则不能。例如:

std::copy(prevData, prevData + LENGTH, currData);

(我假设您要将 prevData 复制到 currData,就像我在这里所做的那样,而不是像其他方式一样你为memcpy做了什么?)

答案 1 :(得分:0)

如果不是作业(那是你的标签?)我建议使用单个unordered_map或地图。你对它的概念还没有结合在一起 - 最好简化它并一次解决一件事而不是咬得比你能咀嚼的多。如果你想要一个树的哈希映射,我建议你从可以依赖的C ++ STL容器开始构建,然后 - 如果你不应该将它们用于这个任务 - 一个接一个地替换它们你保持高级用法/测试工作正常。这意味着:

typedef vector<map<T> > Container;
Container container;

您可以使用container.resize(n)用n个空映射填充容器,或者将容器从之前的大小增加到新的容器,并且额外的映射为空。

真的,从那开始吧。然后,如果你必须作为练习,独立实现每个向量和映射,并使用简单的独立测试用例测试它们的用法,然后再将它们插回到混合哈希映射中。

听起来我可能听起来有些苛刻,所以让我们通过一些问题来看看我所说的一些误解:

  

无论如何,我很难搞清楚   如何做一些事情,比如   设置哈希表,这是一个   数组为NULL,还有memcpy'ing BST   从一个表到另一个表的对象。

我的建议是保持简单,做一些明显而干净的事情。如果必须使用数组而不是向量,那么如果它在堆栈中:

X* buckets[N];
for (int i = 0; i < sizeof buckets / sizeof buckets[0]; ++i)
    array[i] = NULL;

如果它在堆上:

X** p_buckets = new X*[N];
for (int i = 0; i < N; ++i)
    array[i] = NULL;

这比memset()慢,但它简单易懂,让你习惯于考虑循环容器,进行你想要的操作。有更多的C ++方法,但是对于其他任意任务使用相同的迭代样式更难,所以坚持这一点直到你完全熟悉它。

  

BST * prevData;   BST * currData;

     

据我了解,我认为我必须重载=和==运算符以允许设置   数组元素为NULL,这是正确的吗?我真的不清楚如何实现所有   这个,但是继续谷歌的例子,我得到了:

     

BST&安培; BST :: operator =(int null);   bool BST :: operator ==(int null);   ==运算符重载是检查特定数组索引是否等于NULL。   我假设我需要一些额外的代码,而不仅仅是原型,这是   我来的地方。

你有两个指向BST的指针。您的哈希表是这样的对象的数组,但它只是您的注释之一,建议您将这些表示为指向两个这样的哈希表的指针(而不是在迭代通过哈希表期间记录非NULL元素的临时变量)。它们应该是BST **,因为它们指向哈希表中的第一个BST *。但是,这是实现哈希表的一种非常危险的方法,因为客户端使用指向哈希表的指针而不是指向某个类的指针,该类提供哈希表概念的安全实现。使用这样的指针,他们所能做的只是索引到特定的BST,但是与您打算维护哈希表的函数没有关联,也没有跟踪当前有多少桶的变量,有多少元素它包含等等。你应该把你的数组放到一个提供所有这些的类中;有很多设计决定,但看起来应该是这样的:

template <typename Key, typename Value>
class Hash
{
  public:
    Hash() : p_(NULL), size_(0), num_buckets_(0) { }

    // find/make entry for Key, giving read/write access to the current/a-default value
    Value& operator[](const Key&);        
    const Value& operator[](const Key&) const;

    // try to find an entry, throw an exception if not found...
    Value& at(const Key&);
    const Value& at(const Key&) const;

    // report whether a key is already in the hash table...
    bool has_key(const Key&) const;

    int size() const;

  private:
    BST* p_;
    int num_buckets_;
    int size_;
};

(再一次,我只能建议您首先尝试使用p_替换为该地图矢量)。

  

第二点是memcpy,编译器不允许这样做。

     

memcpy(prevData [x],currData [x],sizeof(BST)* height);

     

抱怨

     

错误C2664:'memcpy':无法将参数1从'BST'转换为'void *'   没有可用于执行此转换的用户定义转换运算符,或   无法调用运算符

将一个哈希表中的一个桶中的所有内容复制到另一个哈希表中的同一个桶中是一个非常奇怪的请求。例如,如果存储桶数量不同或散列函数不同,那么您可能会损坏目标存储桶。无论如何,我建议你实现一个带有值语义的BST类(即复制构造函数和operator =复制现有树)。然后你可以简单地使用:

prevData.buckets[x] = currData.buckets[x];

(注意:运算符应该在哈希表中查找,并且给定键类型应该是int,你不想使用相同的表示法来复制整个桶 - 你不能重载函数如果两者都具有相同的签名。这就是为什么我在这里显示桶是BST的暴露容器 - 暴露这种中断封装;在实际类中,你只是不希望用户甚至不知道桶(或BST)(。) / p>