我正在尝试实现一个哈希表类。我面临的问题是如何正确地重载方括号运算符,以便从哈希表中获取键的值可以区别于将键设置为值。
到目前为止,这是班级的样子:
template <typename K, typename V>
class HashTable {
typedef pair<K, V> KeyVal;
avl_tree <KeyVal> **TABLE;
unsigned TABLESIZE;
public:
HashTable( const unsigned & );
V& operator [] ( const K& ); //Setter
const V& operator [](const K&) const; //Getter
typedef unsigned (*hashtype)(const K&);
static hashtype Hash;
~HashTable();
};
这是括号中每个重载的实现:
template <typename K, typename V>
V& HashTable<K, V>::operator [] ( const K& ret ) {
unsigned index = HashTable<K, V>::Hash(ret) % TABLESIZE;
avl_tree <KeyVal> *ptr = AVL_TREE::find(TABLE[index], KeyVal(ret, 0));
if ( ptr == None ) ptr = (TABLE[index] = AVL_TREE::insert(TABLE[index], KeyVal(ret, 0)));
return ptr->data.second;
}
template <typename K, typename V>
const V& HashTable<K, V>::operator [](const K& ret) const {
avl_tree <KeyVal> *ptr = AVL_TREE::find(TABLE[HashTable<K, V>::Hash(ret) % TABLESIZE], KeyVal(ret, 0));
if (ptr == None) throw "Exception: [KeyError] Key not found exception.";
return ptr->data.second;
}
现在,如果我这样做:
cout << table["hash"] << "\n"; //table declared as type HashTable<std::string, int>
我输出0,但我希望它使用重载方括号的getter实现;即这应该抛出异常。我该怎么做?
答案 0 :(得分:2)
当成员函数或运算符的等效const
和非const
重载可用时,在非const
实例上调用方法时,将选择非const。仅当实例为const
时,或者通过const
引用或指针访问时,才会选择const
重载:
struct Foo
{
void foo() {}
void foo() const {}
};
void bar(const Foo& f) { f.foo();}
void baz(const Foo* f) { f->foo(); }
int main()
{
Foo f;
f.foo(); // non-const overload chosen
bar(f); // const overload chosen
bar(&f); // const overload chosen
const Foo cf; // const instance
cf.foo(); // const overload chosen
const Foo& rf = f; // const reference
rf.foo(); // const overload chosen
}
答案 1 :(得分:2)
处理这种情况的常用方法是让operator[]
返回代理。
然后,对于代理重载operator T
,大致与您上面的const
重载相同。像非const版本一样重载operator=
。
template <typename K, typename V>
class HashTable {
typedef pair<K, V> KeyVal;
avl_tree <KeyVal> **TABLE;
unsigned TABLESIZE;
template <class K, class V>
class proxy {
HashTable<K, V> &h;
K key;
public:
proxy(HashTable<K, V> &h, K key) : h(h), key(key) {}
operator V() const {
auto pos = h.find(key);
if (pos) return *pos;
else throw not_present();
}
proxy &operator=(V const &value) {
h.set(key, value);
return *this;
}
};
public:
HashTable( const unsigned & );
proxy operator [] ( const K& k) { return proxy(*this, k); }
typedef unsigned (*hashtype)(const K&);
static hashtype Hash;
~HashTable();
};
使用它时基本上有两种情况:
some_hash_table[some_key] = some_value;
value_type v = some_hash_table[some_key];
在这两种情况下,some_hash_table[some_key]
都会返回proxy
的实例。在第一种情况下,您将分配给代理对象,以便调用代理operator=
,并将其传递给some_value
,以便将some_value
添加到代理对象中以key
为关键字的表。
在第二种情况下,您尝试将类型为proxy
的对象分配给类型为value_type
的变量。显然不能直接赋值 - 但是proxy::operator V
返回基础Hashtable
的值类型的对象 - 所以编译器调用它来生成一个可以赋值给{{1}的值}}。反过来,它检查表中是否存在正确的密钥,如果不存在则抛出异常。