C++哈希相关遇错
问题:不能访问私有成员

这个报错的核心原因很简单:_tables 是 HashTable 类的私有成员,你在类外面的 test5 函数里直接访问它,编译器就会报 inaccessible(不可访问)的错误。
定义 HashTable 时,_tables 写在了 private 区域:
template<class K, class V>
class HashTable
{
public:
// ... 公开接口
private:
vector<HashData<K, V>> _tables; // 私有成员
};
private成员只能被类内部的函数访问,外部代码(比如你的test5)是不能直接碰的。- 你在
test5里写hs._tables.size(),就是在直接访问私有成员,编译器直接拒绝。
问题:要重载才

hs._tables[i] 的类型是 HashData<double, double>,而你没有给这个结构体重载 operator<<,所以 cout 根本不知道怎么打印它
Size() 函数的注意点
之前的 Size() 如果是用 _tables.size() 实现的,那它返回的是底层数组的容量,不是有效元素的个数。
_tables.size():哈希表的桶总数_size:真正插入进去的元素个数
所以你需要在 Insert() 和 Erase() 里维护这个 _size 变量:
问题


test4回报错,5不报错

原因就是这里,test4中,第三个参数的显示传入的。但insert函数中第三个参数用的是缺省值,所以两个不是同类对象,不能访问不同类型的私有成员
HashTable<string, string, StringHashfunc<string>> hs;
问题:类型+()就是匿名对象吗
类型()
这就是匿名对象。没有名字,临时创建,用完就销毁。
举 3 个例子你马上彻底懂
1. int()
int()
= 匿名的 int 对象,值 = 0
2. string()
string()
= 匿名的空字符串对象
string s("hh");
- 这是定义一个名为
s的string变量,并调用构造函数,用"hh"初始化它。 - 变量
s在它所在的作用域内一直存在,后面可以继续使用,比如s.append("!")。 - 这是有名对象。
string("hh");
- 这是创建一个匿名
string对象,内容为"hh",没有名字。 - 这行代码执行完,这个对象就立刻被销毁了,后面再也用不到它。
3. HashFunc()
HashFunc<K>()
= 匿名的哈希函数对象
为什么哈希表那里要写 Hash()(key)?
你看到的:
Hash()(key)
拆解:
Hash()→ 创建一个匿名哈希对象(key)→ 调用这个匿名对象的 operator ()
合起来就是:创建临时哈希对象 → 立刻调用它计算哈希值
问题:


先看 Date 类代码
struct Date
{
int _year, _month, _day;
Date(int year, int month, int day)
: _year(year), _month(month), _day(day)
{}
};
关键点来了:写了一个带参数的构造函数!
- C++ 铁律:只要你写了任何用户自定义的构造函数(哪怕只有一个),编译器就不会再自动生成默认构造函数了。
- 所以,
Date类现在没有默认构造函数(也就是Date()这种无参构造)。
二、再看 pair<Date, int> 的默认初始化
std::pair 的默认构造,是这样的:
pair() : first(), second() {}
它会尝试对两个成员做默认初始化:
first():调用Date的默认构造函数second():调用int的默认构造(没问题,内置类型默认是 0)
但 Date 没有默认构造,所以 pair<Date, int> 的默认构造函数,就会被编译器隐式删除,一用就报错。
三、报错信息直接给你 “破案线索”
你当时的报错是:
no matching function for call to 'std::pair<Date, int>::pair()'
翻译过来就是:
找不到
pair<Date, int>的无参构造函数
为什么找不到?因为它被删除了。为什么被删除?因为它的成员 Date 没有默认构造,编译器无法生成有效的 pair 默认构造。
四、以后怎么快速判断?记住这三步
- 看类的构造函数:有没有写带参数的构造?写了,就没有自动默认构造了。
- 看它的使用场景:是不是在做
T obj;这种无参初始化?比如pair<Date, int> p;。 - 看报错提示:报错里如果出现
no matching function for call to '...::...()',就是在说找不到无参构造,那肯定是某个成员 / 类型没有默认构造。
问题:

问题根源
报错 passing 'const Date' as 'this' argument discards qualifiers 说明:
- 你的哈希函数
operator()接收的是const Date& key,也就是一个常引用 - 你调用了
key.total(),但total()不是const成员函数 - C++ 规定:const 对象只能调用 const 成员函数,否则会被视为 “可能修改对象”,直接报错
修正方案:给 total() 加上 const 修饰
把 total() 函数改成 const 成员函数:
size_t total() const // 关键:加上 const
{
return (_day + _month + _year);
}
const修饰的成员函数,承诺不会修改对象的任何成员变量- 这样
const Date& key就能安全调用它了,编译器也不会报错
问题:模板定义顺序


HashTable 模板写在了 Equal_to 定义的前面!
// 顺序错误!
template <class K, class V, class Hash = Hashfunc<K>, class Equal = Equal_to<K>>
class HashTable { ... };
template <class T>
struct Equal_to { ... };
当编译器读到 HashTable 的模板参数 Equal_to<K> 时,Equal_to 这个名字还没定义,所以直接报错 'Equal_to' does not name a type。
正确的代码顺序
必须先定义 Equal_to,再定义 HashTable
补充:模板的 “前向声明”
如果不想调整顺序,也可以给 Equal_to 加个前向声明,告诉编译器 “这个名字后面会定义”:
// 前向声明,告诉编译器 Equal_to 是一个模板 struct
template <class T>
struct Equal_to;
问题:传参错误

错误的代码
if (equal(_tables[hashi]._kv.first) == key)
你只给 equal 传了一个参数,但 Equal_to 仿函数的 operator() 需要两个参数!
Equal_to<T>的定义是:bool operator()(const T& a, const T& b) const- 它是用来比较
a和b是否相等的,所以必须同时传两个值。
修正后的正确写法
把两个值都传给 equal,去掉多余的 == key:
if (equal(_tables[hashi]._kv.first, key))
报错原文:
no match for call to '(Equal_to<std::string>) (std::string&)'
翻译:
没有找到匹配的函数调用:用
Equal_to<std::string>这个对象,调用(std::string&)这个单参数版本。
重点是这两个词:
Equal_to<std::string>:用的仿函数类型(std::string&):调用时传的参数数量 / 类型
这就直接说了:给仿函数传的参数不对
更多推荐
所有评论(0)