std::сортировка полиморфных типов не выполняется должным образом

#c #polymorphism #overloading

Вопрос:

Я взял пример кода из принципа ch9 Open Closed в гибкой разработке программного обеспечения, как показано ниже, который должен сортировать фигуры по приоритету в порядке, указанном таблицей typeOrderTable в приведенном ниже коде. Ну, мне действительно пришлось добавить основной и тестовый код, но я в значительной степени скопировал код книги. Но вывод показывает, что он не сортируется в соответствии с таблицей. И если я попытаюсь отладить код, путь к коду не будет указывать функцию Shape::Предшествует.

Как я могу это исправить?

Код:

 #include <typeinfo>
#include <string>
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

class Shape {
public:
    virtual void Draw() const = 0;
    bool Precedes(const Shapeamp; s) const;
    bool operator<(const Shapeamp; s) const {
        return Precedes(s);
    }

private:
    static const char* typeOrderTable[];
};

bool Shape::Precedes(const Shapeamp; s) const {
    const char* thisType = typeid(*this).name();
    const char* argType = typeid(s).name();

    bool done{ false };
    int thisOrd{ -1 };
    int argOrd{ -1 };
    for (int i = 0; !done;   i) {
        const char* tableEntry = typeOrderTable[i];
        if (tableEntry != 0) {
            if (strcmp(tableEntry, thisType) == 0)
                thisOrd = i;
            if (strcmp(tableEntry, argType) == 0)
                argOrd = i;
            if (argOrd >= 0 amp;amp; thisOrd >= 0)
                done = true;
        }
        else done = true;
    }
    return thisOrd < argOrd;
}


class Square : public Shape {
public:
    virtual void Draw() const {
        cout << "squaren";
    }
};

class Circle : public Shape {
public:
    virtual void Draw() const {
        cout << "circlen";
    }
};

class Rectangle : public Shape {
public:
    virtual void Draw() const {
        std::cout << "rectanglen";
    }
};

const char* Shape::typeOrderTable[] = {
    typeid(Circle).name(),
    typeid(Rectangle).name(),
    typeid(Square).name(),
    0
};

void DrawAllShapes(vector<Shape*> shapes) {
    vector<Shape*> orderedList = shapes;
    sort(orderedList.begin(), orderedList.end());

    for (auto shape : orderedList) {
        shape->Draw();
    }
}

int main() {
    Shape* circle = new Circle();
    Shape* square = new Square();
    Shape* rectangle = new Rectangle();
    Shape* rectangle2 = new Rectangle();

    vector<Shape*> shapes{ rectangle, square, circle, rectangle2 };
    DrawAllShapes(shapes);
    /* should print:
    circle
    rectangle
    rectangle
    square

    but instead prints:
    rectangle
    square
    rectangle
    circle

    ie unsorted - actually it is random in the output
    */
}
 

Комментарии:

1. При сортировке сравниваются значения указателей (т. Е. адреса), а не содержимое, на которое указано. Вам нужно использовать пользовательский компаратор при вызове сортировки.

2.Примечание: начиная с C 11 не рекомендуется использовать необработанные указатели и вручную очищать память. Использовать std::unique_ptr godbolt.org/z/Prbhdb

Ответ №1:

Вам нужно изменить вызов на std::sort (…), чтобы использовать компаратор. Как у вас есть, это указатели на сортируемые фигуры, а не фигуры, поэтому operator< определенные для фигур не будут вызываться, вместо этого будут сравниваться числовые значения указателей.

Один из способов исправить это-отсортировать следующим образом

 sort(orderedList.begin(), orderedList.end(),
    [](Shape* s1, Shape* s2) { return s1->Precedes(*s2); }
);
 

предоставление лямбда Shape* -кода для фактического сравнения.