简体   繁体   English

关于类和多态的疑惑

[英]Doubts about classes and polymorphism

I'm trying to build a hash table class in C++ using the chaining method, a minimal example class is:我正在尝试使用链接方法在 C++ 中构建一个 hash 表 class,最小示例 class 是:

template <class V>                                                                  
class HashTable {                                                                                                                                                                                                            
private:                                                                                                       
  //some parameters to define the hash_table                                                                                                  
  HashFunc * h;  //family of hash functions                                                                                                                                                                                                                                                          
public:                                                                                                       
  /*other functions*/                                                                       
};

I'm having some troubles with the member HashFunc * h , which is the hash function I intend to use to store pairs <key,value> in the hash table.我在使用成员 HashFunc HashFunc * h遇到了一些麻烦,它是 hash function 我打算用来在 hash 表中存储对 <key,value> 。 In my main , I need to build two different hash tables, one which hashes integers and another one which hashes strings.在我的main中,我需要构建两个不同的 hash 表,一个散列整数,另一个散列字符串。

My doubts are:我的疑问是:

  1. A natural choice for me would be to use polymorphism for the hash function in the following way (mind that I have limited experience with classes and polymorphism):对我来说,一个自然的选择是通过以下方式对 hash function 使用多态(请注意,我对类和多态的经验有限):
class HashFunc{
public:
  virtual int operator()()=0;
}
    
class IntegerHashFunc: public HashFunc
{
  //parameters to hash integers
 public:
  int operator()(int x){
    //operations for integer hashing
  }
}

class StringHashFunc: public HashFunc
{
  //parameters to hash strings
  IntegerHashFunc h_integer; //string->integer->integer hash
  public:
    int operator()(string name){
      int result=0;
      //operations for string hashing
      return h_integer(result); //I need to hash the integer resulting from string "hashing"
    }
}

But this won't work because the operator()(string name) in StringHashFunc has different arguments and thus doesn't override the virtual method in the base class. How to make this work?但这行不通,因为 StringHashFunc 中的operator()(string name)具有不同的StringHashFunc ,因此不会覆盖 base class 中的virtual方法。如何使它工作?

  1. I'm not sure on how to make this work in the constructor for the HashTable class: how to choose between the two methods?我不确定如何在HashTable class 的构造函数中进行这项工作:如何在这两种方法之间进行选择? Should I just use a flag in the constructor like:我应该只在构造函数中使用一个标志,例如:
template<class V>
HashTable<V>::HashTable(/*args*/, int flag){
  //other parameters
  switch(flag){
    case 1:
      h=new IntegerHashFunc(/*args for integer hashing*/);
    case 2:
      h=new StringHashFunc(/*args for string hashing*/);
  }
}

or is there a better way?或者,还有更好的方法?

  1. Is there a better and more natural way to do what I want to do?有没有更好更自然的方式来做我想做的事? For example, I tried using a single class HashFunc with two overloads operator()(int) and operator()(string) , but I don't want to "carry" around string parameters and methods if I'm working just with integers.例如,我尝试使用带有两个重载operator()(int)operator()(string)的单个 class HashFunc ,但如果我只使用整数,我不想“携带”字符串参数和方法.

TL;DR - the answer to all questions is "use templates, not polymorphism". TL;DR - 所有问题的答案都是“使用模板,而不是多态性”。

A natural choice for me would be to use polymorphism for the hash function in the following way (mind that I have limited experience with classes and polymorphism):对我来说,一个自然的选择是通过以下方式对 hash function 使用多态(请注意,我对类和多态的经验有限):
But this won't work because the operator()(string name) in StringHashFunc has different arguments and thus doesn't override the virtual method in the base class. How to make this work?但这行不通,因为 StringHashFunc 中的 operator()(string name) 具有不同的 arguments,因此不会覆盖 base class 中的虚方法。如何使它工作?

You cannot.你不能。 In order to make the derived class non abstract, you need to override all pure virtual functions.为了使派生的class成为非抽象的,需要覆盖所有的纯虚函数。 And even if you add another overload with parameter, it doesn't help, because you can't call those overloads with base class pointer.即使您添加另一个带参数的重载,也无济于事,因为您无法使用基指针 class 调用这些重载。
Theoretically, you can do dynamic_cast to determine what the actual type is (in a long, long chain of if statements), but that's discouraged.理论上,您可以执行dynamic_cast以确定实际类型是什么(在一长串if语句中),但不鼓励这样做。

I'm not sure on how to make this work in the constructor for the HashTable class: how to choose between the two methods?我不确定如何在 HashTable class 的构造函数中进行这项工作:如何在这两种方法之间进行选择? Should I just use a flag in the constructor like:我应该只在构造函数中使用一个标志,例如:
or is there a better way?或者,还有更好的方法?

One option would be to use type traits to select the right branch (assuming you really, really want to use polymorphism):一种选择是将类型特征用于 select 正确的分支(假设您真的非常想使用多态性):

if(std::is_same_v<V, int>) 
    h=new IntegerHashFunc(/*args for integer hashing*/);
else if(std::is_same_v<V, std::string>)
    h=new StringHashFunc(/*args for string hashing*/);

Is there a better and more natural way to do what I want to do?有没有更好更自然的方式来做我想做的事? For example, I tried using a single class HashFunc with two overloads operator()(int) and operator()(string), but I don't want to "carry" around string parameters and methods if I'm working just with integers.例如,我尝试使用带有两个重载 operator()(int) 和 operator()(string) 的单个 class HashFunc,但如果我只使用整数,我不想“携带”字符串参数和方法.

Yes, use templates, like the standard library hash table (aka.std::unordered_map ) does:是的,使用模板,就像标准库 hash 表(又名std::unordered_map )一样:

template<typename T>
class HashFunc{
public:
  int operator()(const T&) const;
};

template<>
class HashFunc<int>{
public:
  int operator()(const int&) const {
    // do calculations for int
  }
};

template<>
class HashFunc<std::string>{
public:
  int operator()(const std::string&) const {
    // do calculations for std::string
  }
};

//etc... for all other specializations

template <class V>                                                                  
class HashTable {                                                                                                                                                                                                            
private:                                                                                                       
  //some parameters to define the hash_table                                                                                                  
  HashFunc<V> h;  //family of hash functions                                                                                                                                                                                                                                                          
public:                                                                                                       
  /*other functions*/                                                                       
};

Or better yet, use the already existing std::hash , which does exactly this, but is already implemented.或者更好的是,使用已经存在的std::hash ,它就是这样做的,但已经实现了。

Use policy based design and it will be much simpler.使用基于策略的设计,它会简单得多。

First create your hash functions objects:首先创建您的 hash 函数对象:

struct IntegerHashFunc
{
  int operator()(int x){ return x; }
};

struct StringHashFunc
{
  IntegerHashFunc h_integer; //string->integer->integer hash
    int operator()(string name){
      int result=0;
      return h_integer(result);
    }
};

Your HashTable class will take the Hash function as a template parameter.您的HashTable表 class 会将 Hash function 作为模板参数。

template <typename Key, typename Val, typename HashFunctionPolicy = IntegerHashFunc>
class HashTable {                                                                                                                                                                                                            
private:                                                                                                       
  //some parameters to define the hash_table                                                                                                                                                                                                                                                         
public:                                                                                                       
  /*other functions*/
  void somefunction(Key key)
  {
      HashFunctionPolicy f;
      auto x = f(key);
  }                                                                   
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM