S. Saad
S. Saad

Reputation: 333

Child class will not call inherited function from template base class

Below is the code I have. I stripped stuff not related to the issue to keep this concise:

IChip.hpp (Root abstract class)

class IChip {
    public:
    virtual bool test() noexcept = 0;
};

IMemory.hpp (Abstract with some functions common to all Memories, read/write for illustration)

#include "IChip.hpp"

template <typename TAddr, typename TWord>
class IMemory: public IChip {
    protected:
    ...

    public:
    virtual TWord read(const TAddr addr) const noexcept = 0;
    virtual void write(const TAddr addr, const TWord data) const noexcept = 0;
    ...
    bool test() noexcept final override;
};

IMemory.cpp

#include "IMemory.hpp"

template <typename TAddr, typename TWord>
bool IMemory<TAddr, TWord>::test() noexcept {
    std::cout << "IMemory:test()" << std::endl;
    ...
    return true;
}

// Explicit instantiation. (Actually resides in a separate file IMemory.impl.cpp, but included here for clarity)
template class IMemory<uint16_t, uint8_t>;

HM62256.hpp (again read/write for illustration)

#include "IMemory.hpp"

class HM62256: public IMemory<uint16_t, uint8_t> {
    private:
    ...

    public:
    ...
    uint8_t read(uint16_t addr) const noexcept final override;
    void write(uint16_t addr, uint8_t data) const noexcept final override;
    ...
};

HM62256.cpp

#include "HM62256.hpp"

uint8_t HM62256::read(uint16_t addr) const noexcept {
    uint8_t result = 0;
    ...
    return result;
}

void HM62256::write(uint16_t addr, uint8_t data) const noexcept {
    ...
}

main.cpp

int main(int argc, char *argv[]) {
    const uint8_t ADDR_PINS[] = {4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18};
    const uint8_t DATA_PINS[] = {19, 20, 21, 22, 23, 24, 25, 26};
    HM62256 *device = new HM62256(ADDR_PINS, DATA_PINS, 2, 3, 27);

    device->test();    // (1)

    delete device;
}

My primary issue is as follows:

My secondary issue is, since the code compiles fine, that function call at (1) must call something, right? WHAT does it call?

Additional info:

Upvotes: 1

Views: 152

Answers (1)

S. Saad
S. Saad

Reputation: 333

So, as @Quimby suggested in the comments, my issue was somewhere else in my code.

How I caught the issue:

  • Enabled some sanitization flags for the compiler and linker. This made the compiler complain about a few things that I had wrong, some of which were probably the source of my issues
add_compile_options(-fsanitize=address)
add_link_options(-fsanitize=address -static-libasan)

What was the issue in my case:

I frankly do not know. Most probably, something was corrupting the vtable. I have a few suspects though:

  • I was incrementing a const variable inside a member function in IMemory, for which the compiler did not complain before adding the sanitization flags.
  • I was making use of the formatting library from C++20. Again the compiler did not complain before adding the sanitization flags, but after complained that it could not find that include. This leads me to believe that either the toolchain itself is broken OR my install of the toolchain is broken.
  • I had a couple of functions in IMemory with default arguments both in the declaration and the definition. After adding the sanitization flags, the compiler complained about that. The fix is to put the default value for the argument only in the declaration.

After fixing these three, the compiler happily compiled the code and the expected results showed up. Note that I had to statically link libasan for the sanitization flags to work.

Upvotes: 1

Related Questions