Search code examples
c++inheritanceinterfaceabstract-class

Calling function that was declared virtual in interface (and implemented in derived class) inside base abstract class


I have the following inheritance model:

   interface      abstract class   concrete derived class
_________________________________________________________
IPriorityQueue -> APriorityQueue -> UnsortedPriorityQueue

My member function was declared purely virtual in the interface. In the abstract class, I want to use size() to already implement empty(), since if size = 0, then the priority queue is empty. size() is properly implemented in the derived class.

#include <list>

template <typename K, typename V>
class   IPriorityQueue
{
    public:
        virtual int     size(void)  const = 0;
        virtual bool    empty(void) const = 0;
};

template <typename K, typename V>
class   APriorityQueue : virtual public IPriorityQueue<K, V>
{
    public:
        bool    empty(void) const { return (!size()); }
};

template <typename K, typename V>
class   UnsortedPriorityQueue : virtual public APriorityQueue<K, V>
{
    private:
        std::list<V>    _list;
    public:
        int             size(void)  const { return (this->_list.size()); }
};

int main()
{
    UnsortedPriorityQueue<int, char>    test;
}

However, I get the following error:

../../libft/APriorityQueue.hpp:49:37: error: there are no arguments to 'size' that depend on a template parameter, so a declaration of 'size' must be available [-fpermissive]
   bool empty(void) const { return (!size()); }
                                     ^~~~
../../libft/APriorityQueue.hpp:49:37: note: (if you use '-fpermissive', G++ will accept your code, but allowing the use of an undeclared name is deprecated)

I read in some other answers on StackOverflow that one has to specify the namespace, so I modified it the following way:

        bool    empty(void) const { return (!IPriorityQueue<K, V>::size()); }

But now I get a linker error complaining that IPriorityQueue<K, V>::size() is not implemented:

main.o:main.cpp:(.text$_ZNK14APriorityQueueIiNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE5emptyEv[_ZNK14APriorityQueueIiNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE5emptyEv]+0x28): undefined reference to `IPriorityQueue<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::size() const'
collect2.exe: error: ld returned 1 exit status

Is there any way I can figure this out? Is such a design even possible? Thank you in advance


Solution

  • Just replace

    bool    empty(void) const { return (!size()); }
    

    with

    bool    empty(void) const { return (!this->size()); }//note i have added this->
    

    and that will solve your problem.

    Here's the rule

    the compiler does not look in dependent base classes when looking up nondependent names .

    Here's a good article for reading more about this.