Hello everyone,

I've got an interesting situation. There are three classes [named "A", "B" and "C"], all derived from a abstract base class [named "base"]. However, in my program, I need to sort a vector of "base" object in a way such that objects of type A are less than B, which are less than C.

In order to achieve this, I need to add pure virtual function to the base class like "bool isA(), bool isB()" etc, which in the derived class would return the appropriate value.

However, this appear to me as a bit messy and perhaps I am doing something against the OOP philosophy, since if I would add a derived class D, I'd have to modify every class!

How would you handle this situation?

--
E

Recommended Answers

All 9 Replies

It takes a little thought in designing your base class for polymorphism. Without any clue as to the data you're working with, I'd start with something like this:

class base {
public:
    virtual data_type value() const = 0;

    int compare(const base& lhs, const base& rhs)
    {
        if (lhs.value() == lhs.value())
            return 0;

        return lhs.value() < rhs.value() ? -1 : +1;
    }
};

Assuming data_type supports operator== and operator<, classes A, B, and C need only wrap their corresponding data into an object of that type and return it. Then in your sort all you need to do is call the compare member function. Adding a new class D would only require a suitable override of the abstract member function value().

Thank you for your answer.

But, in my case, the classes A, B and C don't contain values by which they could get sorted and that's the trick.

More ideas are welcome!

Hmmm, Perhaps the dynamic_cast pointer could achieve the desired result?

But, in my case, the classes A, B and C don't contain values by which they could get sorted and that's the trick.

Of course they do! That's the point of the value function Narue suggested. You override that function in each of your derived classes to return a value that reflects the ordering you desire.

If the requirement is that each derived class should have no knowledge of the relative ordering of objects of that class with respect to objects of the other derived classes (any such knowledge should be localized to that part of the program where one needs to sort these objects), a non-intrusive technique has to be used. Since these are polymorphic types, you can create a predicate for the sort using RTTI. eg. to sort on type,

struct base { virtual ~base() {} /* ... */ };
struct A : base { /* ... */ } ;
struct B : base { /* ... */ } ;
struct C : base { /* ... */ } ;
struct D : A { /* ... */ } ;

struct compare_types
{
    bool operator() ( const base* first, const base* second ) const
    {
        static const std::type_info* tinfo[] = { &typeid(A), &typeid(B), &typeid(C), &typeid(D) } ;
        enum { N = sizeof(tinfo)/sizeof(*tinfo) } ;

        // check for nullptr elided
        int a = 0 ; for( ; a < N ; ++a ) if( typeid(*first) == *tinfo[a] ) break ;
        int b = 0 ; for( ; b < N ; ++b ) if( typeid(*second) == *tinfo[b] ) break ;

        return a < b ;
    }
};

void foo( std::vector<base*>& sequence )
{
    // ...
    std::sort( sequence.begin(), sequence.end(), compare_types() ) ;
    // ...
}

I have read your answer and I must thank everyone for posting.

The proposed solutions all imply that the derived classes could be sorted/ordered the same way numbers can. However, in my case, the "ordering" does not have to follow such rules. For example, A<B<C, but a new class D can be considered to be "less" than A, but "greater" than C.

Nevertheless, the solution given will work in most of the cases, but I still do feel that they violate pure OOP rules in this extraordinary situation.

The proposed solutions all imply that the derived classes could be sorted/ordered the same way numbers can. However, in my case, the "ordering" does not have to follow such rules. For example, A<B<C, but a new class D can be considered to be "less" than A, but "greater" than C.

Then in what sense is it an ordering? And what rules does it have to follow?

You could use a member operator. I think this is probably the closest way to achieve the desired result while still following OOP standards.

class Base
{
 public:
 Base(int i){ival=i;};
 bool operator > (const Base & class2) const;
 bool operator < (const Base & class2) const;
 protected:``
 int ival;
};

bool Base::operator > (const Base & class2) const
{
 return (ival < class2.ival);
}

bool Base::operator < (const Base & class2) const
{
 return (ival > class2.ival);
}

You can add an accessor function to change the value of "ival" at any time to change the order if you see fit. You can also add more classes such as "D" without a need to change any other class. If your asking for a way to, say make "D" larger than A instead of smaller, you could always assign "D" a negative value when calling. If you REALLY want to be able to swap values, you could add another function to swap the values of two.

This is most likely the most seamless way to do this. If this doesn't work then I honestly don't understand what you're looking for.

The proposed solutions all imply that the derived classes could be sorted/ordered the same way numbers can. However, in my case, the "ordering" does not have to follow such rules. For example, A<B<C, but a new class D can be considered to be "less" than A, but "greater" than C.

I don't think that's possible. It defies several logical principles. This for one.

If I'm mistaken, please explain your reasoning.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.