问题:不能访问私有成员

这个报错的核心原因很简单:_tablesHashTable 类的私有成员,你在类外面的 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");
  • 这是定义一个名为 sstring 变量,并调用构造函数,用 "hh" 初始化它。
  • 变量 s 在它所在的作用域内一直存在,后面可以继续使用,比如 s.append("!")
  • 这是有名对象。
 string("hh");
  • 这是创建一个匿名 string 对象,内容为 "hh",没有名字。
  • 这行代码执行完,这个对象就立刻被销毁了,后面再也用不到它。
3. HashFunc()
HashFunc<K>()

= 匿名的哈希函数对象

为什么哈希表那里要写 Hash()(key)

你看到的:

Hash()(key)

拆解:

  1. Hash()创建一个匿名哈希对象
  2. (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 默认构造。

四、以后怎么快速判断?记住这三步

  1. 看类的构造函数:有没有写带参数的构造?写了,就没有自动默认构造了。
  2. 看它的使用场景:是不是在做 T obj; 这种无参初始化?比如 pair<Date, int> p;
  3. 看报错提示:报错里如果出现 no matching function for call to '...::...()',就是在说找不到无参构造,那肯定是某个成员 / 类型没有默认构造。

问题:

问题根源

报错 passing 'const Date' as 'this' argument discards qualifiers 说明:

  1. 你的哈希函数 operator() 接收的是 const Date& key,也就是一个常引用
  2. 你调用了 key.total(),但 total() 不是 const 成员函数
  3. 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
  • 它是用来比较 ab 是否相等的,所以必须同时传两个值。

修正后的正确写法

把两个值都传给 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&):调用时传的参数数量 / 类型

这就直接说了:给仿函数传的参数不对

更多推荐