I've been trying to figure out why I get an error when I try to build this code in QTCreator. I found some other posts similar to this but I think I have a similar but different issue.
In main.cpp I basically have some Filter (a templated struct with a pure virtual function) that I'm creating that returns to me a vector of MyProducts. I give the filter a Specification (a templated struct with a pure virtual function) and a vector of MyProduct to search through.
But I keep getting this error message during the build.
/Users/marcokok/Qt-workspace/Open_Closed_Principle/main.cpp:112: error: allocating an object of abstract class type 'Specification<MyProduct>'
/Users/marcokok/Qt-workspace/Open_Closed_Principle/main.cpp:112:36: error: allocating an object of abstract class type 'Specification<MyProduct>'
AndSpecification<MyProduct> as(cs, ss);
^
/Users/marcokok/Qt-workspace/Open_Closed_Principle/main.cpp:29:18: note: unimplemented pure virtual method 'is_satisfied' in 'Specification'
virtual bool is_satisfied(T* item) = 0;
^
Here is my source code
main.cpp
#include <iostream>
#include <vector>
using namespace std;
enum class ColorTable
{
red,
green,
blue
};
enum class SizeTable
{
small,
medium,
large
};
struct MyProduct
{
string name;
ColorTable color;
SizeTable size;
};
template <typename T> struct Specification
{
virtual bool is_satisfied(T* item) = 0;
};
template <typename T> struct Filter
{
virtual vector<T*> filter(vector<T*> items, Specification<T>& spec) = 0;
};
struct BetterFilter : Filter<MyProduct>
{
vector<MyProduct*> filter(vector<MyProduct *> items, Specification<MyProduct> &spec) override
{
vector<MyProduct*> result;
for (auto& item : items)
{
if (spec.is_satisfied(item))
result.push_back(item);
}
return result;
}
};
struct ColorSpecification : Specification<MyProduct>
{
ColorTable color;
ColorSpecification(ColorTable color) : color(color)
{}
bool is_satisfied(MyProduct* item) override
{
if (item->color == color)
return true;
else
return false;
}
};
struct SizeSpecification : Specification<MyProduct>
{
SizeTable size;
SizeSpecification(SizeTable size) : size(size)
{}
bool is_satisfied(MyProduct* item) override
{
if (item->size == size)
return true;
else
return false;
}
};
template <typename T> struct AndSpecification : Specification<T>
{
Specification<T>& first;
Specification<T>& second;
AndSpecification(Specification<T> first, Specification<T> second) : first(first) , second(second)
{}
bool is_satisfied(T* item) override
{
if (first.is_satisfied(item) && second.is_satisfied(item))
return true;
else
return false;
}
};
int main()
{
MyProduct prod_1{"Apple", ColorTable::green, SizeTable::large};
MyProduct prod_2{"Jeans", ColorTable::green, SizeTable::small};
MyProduct prod_3{"Graphics Card", ColorTable::blue, SizeTable::large};
vector<MyProduct*> items = {&prod_1, &prod_2, &prod_3};
BetterFilter bf;
ColorSpecification cs(ColorTable::green);
SizeSpecification ss(SizeTable::large);
AndSpecification<MyProduct> as(cs, ss);
auto green_things = bf.filter(items, cs);
for (auto& item : green_things)
cout << item->name << " is green." << endl;
auto large_things = bf.filter(items, ss);
for (auto& item : large_things)
cout << item->name << " is large.\n\n" << endl;
// auto large_green_things = bf.filter(items, as);
//for (auto& item : large_green_things)
// cout << item->name << " is large and green." << endl;
return 0;
}
Your compiler tells you where the error occurs.
/Users/marcokok/Qt-workspace/Open_Closed_Principle/main.cpp:112:36: error: allocating an object of abstract class type 'Specification<MyProduct>' AndSpecification<MyProduct> as(cs, ss); ^
The attempt to instantiate Specification<MyProduct>
occurs when using cs
as the first argument to the AndSpecification<MyProduct>
constructor. Creating cs
was fine, but somehow this function call triggers the construction of an abstract class. So let's look at the declaration of that constructor.
AndSpecification(Specification<T> first, Specification<T> second)
The first parameter is passed by value (unlike many of your other parameters). This means that a newly-constructed Specification<MyProduct>
object is initialized from cs
. (The Specification<MyProduct>
sub-object of cs
is looked at, and those data members are copied to the new object.) However, Specification<MyProduct>
is abstract (as are all Specification<T>
classes), so it cannot be constructed. Hence the error.
Change your constructor to accept arguments by reference.
AndSpecification(Specification<T>& first, Specification<T>& second)
// ^ ^
See? It's not as complicated as you made it appear, if you know how to read the error message.