I would change a few things in your code:
- If you want to treat your items polymorphically, you should create heap instances of the derived classes, e.g.
IntItem
, but then use a vector of pointers to the base class, Item
.
- In order to sort items based on the item's data, you could provide a virtual method
getData()
.
- I would definitely not use
unique_ptr
s in the compare function, but just raw pointers; std::ranges
projections fit well here because you can tell sort to first get the raw pointer to each element and the pass it to the compare function.
[Demo]
#include <algorithm> // sort
#include <iostream> // cout
#include <memory> // make_unique, unique_ptr
#include <vector>
class Item
{
public:
virtual int getData() = 0;
virtual void printData() = 0;
};
class IntItem : public Item
{
private:
int data;
public:
explicit IntItem(int d) : data{d} {}
int getData() { return data; }
void printData() { std::cout << data; }
};
struct ItemCompare
{
inline bool operator()(Item* a, Item* b)
{
return a->getData() < b->getData();
}
};
int main()
{
std::vector<std::unique_ptr<Item>> items{};
for (auto&& i : { 10, -15, 40, 0, 100 })
{
std::unique_ptr<Item> newItem = std::make_unique<IntItem>(i);
items.push_back(std::move(newItem));
}
std::ranges::sort(items, ItemCompare{},
[](auto& item_up) { return item_up.get(); });
for (auto& i : items)
{
std::cout << i->getData() << " ";
}
}
// Outputs
//
// -15 0 10 40 100
Now, if you want to add some more subclasses to Item
, e.g. StringItem
, and yet be able to sort a list of generic items, you should provide something to sort on. The example below sorts the items based on the insertion order:
- Items are assigned an ID in the
Item
constructor by using a static counter.
ItemCompare::operator()
compares items by their ID.
[Demo]
#include <algorithm> // shuffle, sort
#include <iostream> // cout
#include <memory> // make_unique, unique_ptr
#include <random> // default_random_engine, random_device
#include <string>
#include <vector>
class Item
{
private:
static inline size_t current_id{};
size_t id;
public:
Item() : id{current_id++} {}
size_t getId() { return id; }
virtual void printData() = 0;
};
class IntItem : public Item
{
private:
int data;
public:
explicit IntItem(int d) : Item{}, data{d} {}
void printData() { std::cout << data; }
};
class StringItem : public Item
{
private:
std::string data;
public:
explicit StringItem(const std::string& d) : Item{}, data{d} {}
void printData() { std::cout << data; }
};
struct ItemCompare
{
inline bool operator()(Item* a, Item* b) { return a->getId() < b->getId(); }
};
int main()
{
std::vector<std::unique_ptr<Item>> items{};
for (auto&& i : { 10, -15, 40 })
{
std::unique_ptr<Item> newItem = std::make_unique<IntItem>(i);
items.push_back(std::move(newItem));
}
for (auto&& i : { "blah", "foo", "meh" })
{
std::unique_ptr<Item> newItem = std::make_unique<StringItem>(i);
items.push_back(std::move(newItem));
}
std::ranges::shuffle(items, std::default_random_engine{ std::random_device{}()});
std::cout << "After shuffling... ";
for (auto& item_up : items) { item_up->printData(); std::cout << " "; }
std::cout << "\n";
std::ranges::sort(items, ItemCompare{},
[](auto& item_up) { return item_up.get(); });
std::cout << "After sorting... ";
for (auto& item_up : items) { item_up->printData(); std::cout << " "; }
std::cout << "\n";
}
// Outputs:
//
// After shuffling... -15 foo meh 40 blah 10
// After sorting... 10 -15 40 blah foo meh