3

I'm new to C++, and I'm trying to write a simple code to compare two objects of subclasses of a parent class called Comparable. I want each subclass to have its own implementation of a method to compare objects based on the data they hold, so I used the virtual keyword:

class Comparable {  
public:
virtual int compare(Comparable *other); 
    };

For example, my subclass HighScoreElement would have its own implementation of compare that would compare the score of the object to the score of another HighScoreElement.

Here is my subclass HighScoreElement:

class HighScoreElement: public Comparable { 
        public: 
virtual int compare(Comparable *other); 
HighScoreElement(string user_name, int user_score); // A constructor
        private: 
int score; 
string name;

 };

But in my compare implementation in HighScoreElement, I first try to check if the current object's data is the same as other's data. But since the pointer to other is of class Comparable and not HighScoreElement, I can't reference other->score at all in my code, even though HighScoreElement is a subclass of Comparable.

Here is the full code so far:

#include <iostream> 
using namespace std; 

class Comparable {
public: 
virtual int compare(Comparable *other);
    };

class HighScoreElement: public Comparable {
public: 
    virtual int compare(Comparable *other);
    HighScoreElement(int user_score, string user_name);
private:
    string name;
    int score; 
};

HighScoreElement::HighScoreElement(int user_score, string user_name) {
name = user_name; 
score = user_score; 
}



int HighScoreElement::compare(Comparable *other) {
if (this->score == other->score) { // Compiler error right here, other->score is invalid.
    // Code to do the comparing if two scores are equal...
}
}

I get a compiler error immediately when I write this code:

if (this->score == other->score)

because other doesn't have data called score, but its subclass, HighScoreElement, does. How can I fix my function implementation so that I can reference the data of "other?" I know my question may sound vague, but any help would be appreciated!

ra1nmaster
  • 662
  • 1
  • 8
  • 21
  • An easy solution would be to use `dynamic_cast(other)`, which returns `nullptr` (`0`) in case `other` does not point to an instance of `HighScoreElement` (or derived from that). There might a better design w/o `dynamic_cast`, though. – dyp Jul 19 '13 at 22:07
  • 2
    Nothing personal, but this code is ugly. Looks like some kind of java-style c++ code with Comparable as interface? My heart is broken. – kvv Jul 19 '13 at 22:24
  • @kw My code, when I began using C++, was much worse. =) The learning process is a muddy road. Peoples' code quality improve as they learn over time. – Jamin Grey Jul 19 '13 at 23:38
  • 1
    Yea, I'm a complete beginner, I know the code is really ugly, but its just for learning purposes. Hence my question :) – ra1nmaster Jul 20 '13 at 03:10
  • @Jamin Grey I cannot disagree. – kvv Jul 20 '13 at 07:43

4 Answers4

1

You could implement a virtual function GetScore(), possibly pure virtual in the base class, and use that instead of accessing the field score in your compare function. Make it a const method. On the other hand, Compare could be a method implemented in the base class, that uses this->GetScore() and other->GetScore()

Code stub:

class A {
   virtual int getScore() const = 0;
   inline bool compare(const A* in) {return (in && this->getScore() == in->getScore());}
   //return false also if "in" is set to NULL
   }


class B : public A {
   int score;
   inline int getScore() const {return score;}
   }
Community
  • 1
  • 1
Antonio
  • 19,451
  • 13
  • 99
  • 197
0

You can cast the pointer passed to HighScoreElement::compare using "dynamic_cast" (it throws a bad_cast exception on failure).

int HighScoreElement::compare(Comparable *other) {
HighScoreElement *h = NULL; 
try
{
    ptr = dynamic_cast<HighScoreElement *>(other); 
}
catch(std::bad_cast const &)
{
    // Handle the bad cast...
}
if (this->score == ptr->score) { 
// Code to do the comparing if two scores are equal...
}
}
SeaBass
  • 121
  • 1
  • 10
  • [expr.dynamic.cast]/9 "The value of a failed cast to pointer type is the null pointer value of the required result type. A failed cast to reference type throws an exception [...]" – dyp Jul 19 '13 at 22:31
0

If you are prepared to accept null pointers, you can use dynamic casts. You can have an overload for the case when you are comparing a HighScoreElement pointer to avoid an unnecessary cast.

#include <iostream> 
using namespace std; 

class Comparable {
public: 
  virtual int compare(Comparable *other) = 0;  // made pure virtual to compile without definition
};

class HighScoreElement: public Comparable {
public: 
  virtual int compare(Comparable *other);
  int compare(HighScoreElement *other); // comparing to a HighScoreElement ptr, no need to dynamic cast
  HighScoreElement(int user_score, string user_name);
private:
  string name;
  int score; 
};

HighScoreElement::HighScoreElement(int user_score, string user_name) {
  name = user_name; 
  score = user_score; 
}

int HighScoreElement::compare(Comparable *other) {
  HighScoreElement * pHSE = dynamic_cast<HighScoreElement*>(other);
  if (pHSE) {
    return compare(pHSE);
  } else {
    return -1; // or however you want to handle compare to non HighScoreElement
  }
}

int HighScoreElement::compare(HighScoreElement *other) {
  if (this->score == other->score) {
    ;
  }
}
A.E. Drew
  • 2,097
  • 1
  • 16
  • 24
  • @DyP Thanks. Seems like I can never got it 100% right. Corrected – A.E. Drew Jul 19 '13 at 22:33
  • Note you should also change your code, it currently contains a possible access violation (as there's no exception, `other->score` might operate on a nullptr). The dispatch is nice; if the `dynamic_cast` returns `0`, the objects are not equal anyway. Note however that `other` might be derived from `HighScoreElement` and therefore only checking `score` might not be sufficient. – dyp Jul 19 '13 at 22:36
-1

Are you sure it's not

compare( Comparable other )

If (this->score == other.score)

Andyz Smith
  • 698
  • 5
  • 20
  • `Comparable` does not contain a member named `score`, and your suggestion would slice any passed object derived from `Comparable`. – dyp Jul 19 '13 at 22:10
  • Well I think something is confused here. OP may be confusing implementing Comparable interface with using Comparable as a type to be passed around. – Andyz Smith Jul 19 '13 at 22:17