2

I don't know why C++ compiler run the base class method (sort method of class Sorting) instead of derived class method (sort method of class SelectionSort).

template <typename T>
class Sorting {
public:
    virtual void sort(T* data, int size, Comparator<T> comparator) const {
    };
};

template <typename T>
class SelectionSort : public Sorting<T> {
public:
    void sort(T* data, int size, Comparator<T> comparator) {
        // my selection sort code
    };
};

template <typename T>
void Array<T>::sort(Sorting<T> algorithm, Comparator<T> comparator) {
    algorithm.sort(data, size, comparator); /// Problem is here !
};

int main() {
    int nums[] = { 2, 1, 3 };
    Array<int> arr(nums, 3);
    SelectionSort<int> sorting = SelectionSort<int>();
    AscendingComparator<int> comparator = AscendingComparator<int>();
    arr.sort(sorting, comparator);
    return 0;
}
  • possible duplicate of [Can a member function template be virtual?](http://stackoverflow.com/questions/2354210/can-a-member-function-template-be-virtual) – NathanOliver Apr 07 '15 at 17:46
  • 2
    For the same reason as if it weren't a template: object slicing. You want both parameters to be reference parameters. – molbdnilo Apr 07 '15 at 17:47
  • try: `void Array::sort(Sorting &algorithm, Comparator comparator) {` – W.F. Apr 07 '15 at 17:47
  • Try taking the algorithm by reference in the array sort: Array::sort(Sorting& algorithm ... – qeadz Apr 07 '15 at 17:48
  • @NathanOliver No, the member function isn't a template in this case. – molbdnilo Apr 07 '15 at 17:48
  • It looks like you should make `Sorting` abstract, so that `sort` is only implemented for its subclasses. Then the compiler can catch this error, avoiding obscure runtime issues. (Either that, or remove the base class altogether, and use another template parameter to inject the algorithm). – Mike Seymour Apr 07 '15 at 17:54

1 Answers1

6

Your specific problem is Object Slicing. You look like you're coming from Java, where this would just work - but in C++, you lose all the important parts of the object when you copy it. What you need to do is take your interfaces by reference:

template <typename T>
void Array<T>::sort(Sorting<T>& algorithm, Comparator<T>& comparator) {
                              ^                         ^
    algorithm.sort(data, size, comparator);
};

And similarly within Sorting::sort() - which needs to take Comparator by reference. Note that had you made Sorting and abstract base class, that is have:

template <typename T>
class Sorting {
public:
    virtual void sort(T* , int , Comparator<T> ) const = 0;
    //                                                ^^^^
};

The compiler would have caught this error for you, as you cannot make an object of type Sorting<T> - which your code would require.

Note also as Angew points out, your SelectionSort class does not actually override Sorting<T>::sort as it is missing the const modifier. The compiler would have pointed this error out to you as well if sort() had been pure virtual in the base class.

There's a few other Java things in your code:

SelectionSort<int> sorting = SelectionSort<int>();
AscendingComparator<int> comparator = AscendingComparator<int>();

should just be:

SelectionSort<int> sorting;
AscendingComparator<int> comparator;
Community
  • 1
  • 1
Barry
  • 286,269
  • 29
  • 621
  • 977