title: undefined symbol: vtable for SomeClass
body: <p>Just ran into these 2 Clang errors:</p>
  
  <pre><code>ld.lld: error: undefined symbol: vtable for HashFn
  &gt;&gt;&gt; referenced by hashFn.h:40 ......
  HashFn::HashFn(int, bool)
  </code></pre>
  
  <p>And</p>
  
  <pre><code>ld.lld: error: undefined symbol: vtable for HashFn
  &gt;&gt;&gt; referenced by hashFn.h:36 ......
  HashFn::HashFn(HashFn const&amp;)
  </code></pre>
  
  <p>hashFn.h --></p>
  
  <pre><code>#ifndef HASHFN_H_
  #define HASHFN_H_
  
  #include "./base.h"
  
  typedef uint64_t uint64Array[30];
  static int precomputedArraySize = sizeof(uint64Array) / sizeof(uint64_t);
  
  inline uint64_t customPow(uint64Array *precomputedPowers, bool usePrecomputed,
      uint64_t base, int exp) {
    if (usePrecomputed &amp;&amp; exp &lt; precomputedArraySize) {
      return (*precomputedPowers)[exp];
    }
  
    // TOOD: Optimization possible here when passed in toSize which is bigger
    // than precomputedArraySize, we can start from the value of the last
    // precomputed value.
    uint64_t result = 1;
    while (exp) {
      if (exp &amp; 1)
        result *= base;
      exp &gt;&gt;= 1;
      base *= base;
    }
    return result;
  }
  
  
  // Functor for a hashing function
  // Implements a Rabin fingerprint hash function
  class HashFn {
   public:
    // Initialize a HashFn with the prime p which is used as the base of the Rabin
    // fingerprint algorithm
    explicit HashFn(int p, bool precompute = true) {
      this-&gt;p = p;
      this-&gt;precompute = precompute;
      if (precompute) {
        uint64_t result = 1;
        for (int i = 0; i &lt; precomputedArraySize; i++) {
          precomputedPowers[i] = result;
          result *= p;
        }
      }
    }
    //virtual ~HashFn(){}
    ~HashFn(){}
  
    virtual uint64_t operator()(const char *input, int len,
        unsigned char lastCharCode, uint64_t lastHash);
  
    virtual uint64_t operator()(const char *input, int len);
  
   private:
    int p;
    bool precompute;
    uint64Array precomputedPowers;
  };
  
  #endif  // HASHFN_H_
  </code></pre>
  
  <p>hashFn.cc --></p>
  
  <pre><code>#include "hashFn.h"
  
  uint64_t HashFn::operator()(const char *input, int len,
        unsigned char lastCharCode, uint64_t lastHash) {
      // See the abracadabra example:
      // https://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_algorithm
      return (lastHash - lastCharCode *
        customPow(&amp;precomputedPowers, precompute, p, len - 1)) *
        p + input[len - 1];
    }
  
  uint64_t HashFn::operator()(const char *input, int len) {
      uint64_t total = 0;
      for (int i = 0; i &lt; len; i++) {
        total += input[i] *
          customPow(&amp;precomputedPowers, precompute, p, len - i - 1);
      }
      return total;
    }
  </code></pre>
  
  <p>There is already a derived class from HashFn:</p>
  
  <pre><code>class HashFn2Byte : public HashFn {
   public:
    HashFn2Byte() : HashFn(0, false) {
    }
  
    uint64_t operator()(const char *input, int len,
        unsigned char lastCharCode, uint64_t lastHash) override;
  
    uint64_t operator()(const char *input, int len) override;
  };
  ......
  </code></pre>
  
  <p>What went wrong? I can vaguely understand this has something to do with the virtual destructor but not sure why the vtable is undefined (if I define all declarations then vtable should be there automatically?).</p>
  
  <p>Also, I'm now playing in Chromium so I don't know how would the fact all files are compiled into a "jumbo" object affect the results. The standalone version of this code (<a href="https://github.com/bbondy/bloom-filter-cpp" rel="nofollow noreferrer">a Node native module</a>) can compile and run normally.</p>
  
  <p>Any input is appreciated! Thanks.</p>