Mathematical Lie
Mathematical Lie

Reputation: 143

Pass vector of objects of derived class to function which takes vector of objects of base class

I'm new to c++ but I have experience with OOP in other languages such as java. I have three classes: class Sortable {...};, class Letter: Sortable {...};, and class Sorter {...};. Sorter has a public function vector<Sortable> sort(vector<Sortable> items_).

In main, I make a vector, vector<Letter> letters; which I give some Letter objects. I then create a Sorter object and use its sort function:

Sorter sorter = Sorter();
vector<Sortable> sortedLetters = sorter.sort(letters);

On that second line I get two errors: No viable conversion from 'vector<Letter>' to 'vector<Sortable>' and No viable conversion from 'vector<Sortable>' to 'vector<Letter>'. That error makes sense but it leaves me with no idea how to make a function which accepts any derived class of a base class.

minimum reproducible example:

#include <iostream>
#include <vector>

using namespace std;

class Sortable {
public:
    virtual int getSortValue() = 0;
};

class Letter: Sortable {
    int sortValue;
public:
    Letter(int f);
    int getSortValue();
};

Letter::Letter(int f) {
    sortValue = f;
}

int Letter::getSortValue(){
    return sortValue;
}

class Sorter {
public:
    Sorter();
    vector<Sortable> sort(vector<Sortable> items_);
};

Sorter::Sorter() = default;

vector<Sortable> sort(vector<Sortable> items_) {
    return items_;
}

int main(int argc, const char * argv[]) {
    Letter a = Letter(1);
    Letter b = Letter(4);
    Letter c = Letter(3);
    Letter d = Letter(2);
    vector<Letter> letters {a,b,c,d};
    Sorter sorter = Sorter();
    vector<Letter> sortedLetters = sorter.sort(letters);
    
    return 0;
}

Upvotes: 1

Views: 85

Answers (1)

Caleth
Caleth

Reputation: 62694

The idiomatic way that this would be done in C++ is to discard class Sortable and class Sorter, and have a free function template sort. Letter could either have an operator <, or you would use a function that defined "less than" for a particular context.

Since C++20 things have gotten slightly nicer, as you can define operator <=> which synthesizes each of < > <= >=, and you can = default a comparison to have it compare each base and member.

template <typename T, typename Pred = std::less<T>> // default comparison is <
/* since C++20 */ requires std::strict_weak_order<Pred, T, T>
std::vector<T> sort(std::vector<T> items, Pred less) {
    // items is a copy, so we aren't mutating the source object
    std::sort(items.begin(), items.end(), less); // or whatever
    return items;
}

class Letter {
    friend bool operator<(const Letter &, const Letter &); // pre C++20 this is sufficient to sort, but doesn't define >, <=, >=
    friend auto operator <=>(const Letter &, const Letter &) = default; // post C++20, defines < > <= >= too
}

bool someSpecificLetterOrder(const Letter &, const Letter &); // for sorting by a different criteria

Upvotes: 2

Related Questions