Issue with template interface... need help.

Since I have said a lot here... I am highlighting the important stuff in bold. The rest is background information that might be useful...

I recently posted a question related to creating a heap template class. The ultimate goal is to create a series of classes that serve a purpose that was overlooked in the Qt library that I need for my current project.

The current "end goal" is a PriorityQueue template that uses a comparer class which is inherited from a "template interface". Basically a pure virtual class template. Perhaps that is the mistake to begin with but hopefully not. (Is this a valid approach?)

The problem I am getting is that when I compile the code, it says my derived comparer class is abstract. I need help figuring out why.

Just in case... I will include all related classes here. I doubt it is relevant but the templates and the classes based off them are in different namespaces.

Here is the comparer "template interface":

1
2
3
4
5
6
7
8
9
// in global namespace
template<class T>
class IIMQOBJECTS_EXPORT IQComparer
{
	virtual int compare(T& a, T& b) = 0;
	virtual bool equals(T& a, T& b) = 0;
	virtual bool isGreaterThan(T& a, T& b) = 0;
	virtual bool isLessThan(T& a, T& b) = 0;
};


Here is the class that is supposed to be non-abstract but isn't recognized as such:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// in the application namespace AND IN SAME project that has the NetEventInfo class
// all functions ARE defined/implemented in a cpp file
class APPCORE_EXPORT NetEventInfoComparer : ::IQComparer<NetEventInfo*>
{
public:
	NetEventInfoComparer();
	~NetEventInfoComparer();

public: //overrides
	virtual int compare(NetEventInfo* A, NetEventInfo* B);
	virtual bool equals(NetEventInfo* A, NetEventInfo* B);
	virtual bool isGreaterThan(NetEventInfo* A, NetEventInfo* B);
	virtual bool isLessThan(NetEventInfo* A, NetEventInfo* B);
};

}


Here is the heap class on which the PriorityQueue is based (inherits from):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// in global namespace
#include "iimqobjects_global.h"
#include "IQComparable.h"
#include <qvector.h>
#include "HeapEnums.h"

#define INCREASE_SIZE 200
#define PARENT(i) (i/2)
#define LEFT(i) (2*i)
#define RIGHT(i) (2*i+1)

template<typename T>
class IIMQOBJECTS_EXPORT QComparerHeap
{

public:
	QComparerHeap(IQComparer<T>* comparerClassInstance);
	//... removed other constructors because they are irrelevant...
	~QComparerHeap();

	void add(const T& item);
	void remove(int i);

	T& at(int i);
	int capacity();
	int count();
	T& largest();
	int size();
	T& smallest();

private:
	void exchange(int i, int j);
	void maxHeapify(int i, int size);
	void minHeapify(int i, int size);

private:
	QVector<T> heap;
	IQComparer<T>* comparer;
	HeapType type;
};


Finally... here is the PriorityQueue class


1
2
3
4
5
6
7
8
9
10
11
12
13
// also in global namespace
#include "iimqobjects_global.h"
#include "QComparerHeap.h"

template<typename T>
class IIMQOBJECTS_EXPORT QPriorityQueue : QComparerHeap<T>
{
public:
	QPriorityQueue(IQComparer<T>* comparerClassInstance);
	//... removed other constructors because they are irrelevant...

	T pop();
};


All these are necessary for a server I am developing. It may help you to know where the error exists in compilation. Basically the error occurs when I instantiate the priority queue which is a log of events that must be easy to add "out of order" events to. (FYI... this is because a backup of unreported events is temporarily kept if the GUI which events get reported to is not available. These are added to the regular log when the GUI becomes available)

NOTE: The server code is in its own DLL/Project which has the same namespace as AppCore (where NetEventInfo and NetEventInfoComparer are defined)

The code that declares the log (priorityQueue): QPriorityQueue<NetEventInfo*> mLog;

The code that produces the error (stating it is an abstract class and that NONE of my pure virtual functions have been defined):
1
2
3
4
5
6
7
8
9
10
ServerEngine::ServerEngine() :
	mServerHost(NULL),
	mLogHost(NULL),
	mRoleInfo(NULL),
	mvBackupLog(NULL),
	mLog(new NetEventInfoComparer()), // THIS LINE
	mServerRole(ServerRoles::all),
	mLoginServer(NULL)
{
}



Last edited on
> The current "end goal" is a PriorityQueue template that uses a comparer class
> which is inherited from a "template interface". Basically a pure virtual class
> template. Perhaps that is the mistake to begin with but hopefully not.
> (Is this a valid approach?)

Consider using std::priority_queue<>
http://en.cppreference.com/w/cpp/container/priority_queue


> The problem I am getting is that when I compile the code, it says my derived comparer class is abstract.
> I need help figuring out why.

In the base class, the parameters are passed by reference.
The derived class does not override the base class functions; instead it adds new virtual functions where the parameters are passed by value.


Make the base class const-correct, and add a virtual destructor:
1
2
3
4
5
6
7
8
9
10
template<class T>
class IIMQOBJECTS_EXPORT IQComparer
{
        virtual ~IQComparer() = default ;

	virtual int compare( const T& a, const T& b) const = 0;
	virtual bool equals( const T& a, const T& b) const = 0;
	virtual bool isGreaterThan( const T& a, const T& b ) const = 0;
	virtual bool isLessThan( const T& a, const T& b) const = 0;
};


In the derived class, pass parameters by reference (using a type alias would help simplify matters):
1
2
3
4
5
6
7
8
9
10
11
12
13
class APPCORE_EXPORT NetEventInfoComparer : ::IQComparer<NetEventInfo*>
{
public:
    NetEventInfoComparer();
    ~NetEventInfoComparer();

    using arg_type = NetEventInfo* ;

    virtual int compare( const arg_type& a, const arg_type& b) const override;
    virtual bool equals( const arg_type& a, const arg_type& b) const override;
    virtual bool isGreaterThan( const arg_type& a, const arg_type& b ) const override;
    virtual bool isLessThan( const arg_type& a, const arg_type& b) const override;
};


Tip: use the override specifier when the intent is to override a virtual function. The compiler can tell us if we haven't overridden it correctly.
http://en.cppreference.com/w/cpp/language/override
Ooops... I should have seen that. Oh well. Thanks! I also appreciate the extra tips. I have used C# for a long time so I am not yet used to the attention to subtle details that C++ often requires.

One thing that would help is to understand what you mean by "const-correct". I know that a const is a variable is not supposed to change but I gather from your statement that there are some implications and meanings that I am not familiar with.
Thanks. FYI the following lines seem to be compiler specific (VS 2012 doesn't like them):

using arg_type = NetEventInfo* ;
Gives "'arg_type': symbol cannot be used in a using declaration

virtual ~IQComparer() = default ;
Gives "illegal pure syntax, must be '= 0'"

They are C++11 features.
http://en.cppreference.com/w/cpp/language/type_alias
http://www.stroustrup.com/C++11FAQ.html#default

These equivalent constructs should work in VS 2012:

1
2
3
4
5
// using arg_type = NetEventInfo* ;
typedef NetEventInfo* arg_type ;

// virtual ~IQComparer() = default ;
virtual ~IQComparer() {} ;


VS 2012 may not support the override specifier either.
Last edited on
It does. Thanks.
Topic archived. No new replies allowed.