Inheritance problem

voodoodrul

Senior member
Jul 29, 2005
521
1
81
So I have done quite a lot of programming over the years. This sounds terribly simple, but I believe it to be flawed in concept given the requirements. I am to create a base Comparator class with a single public method: public int Compare(Type item1, Type item2). This will return a basic 1, 0, -1 depending on how the items compare. There are different Comparison types, and here's the part that is messing with me, I am told to inherit the Comparator class into PriceComparator, CostComparator, etc. This would be fine if I was allowed to directly access the child object, but I am not allowed. I could create a new Comparator cmp = new PriceComparator(); and then access the Compare method in the child. But I'm not allowed to do this.

The goal is to have a single exposed Comparator class, with no knowledge of the children. I assume I need to instantiate a Comparator object and pass in my comparison type. So I would create: Comparator priceComparator = new Comparator("price"); Then I need to call priceComparator.Compare(item1, item2); Comparator would use the specified type (stored in the Comparator object) to decide what to do. But I can't simply call the child classes as this would result in infinitely calling constructors between parent and child until a stack exception occurred.

The real problem lies in what to do with the Compare() method. Since each child (i.e. PriceComparator) class has it own way of calculating comparisons, I have no idea how to get a simple:
Comparator priceComparator = new Comparator("price");
priceComparator .Compare(item1, item2);

to work properly. Can anyone offer some pointers? (no pun intended)

Thanks!
 

Cogman

Lifer
Sep 19, 2000
10,286
147
106
Ok, if I'm understanding your problem correctly, You have 3 classes, a base class and two derived classes. You need each class to perform a comparison, but each has its own method of doing comparisons.

This sounds like a job for virtual functions. You should define Compare as a virtual function and then in each sub-class define it as what you need. Then, if you need to pass the class to a function of some sort, make sure that you pass it by reference or as a pointer. IE

int doStuff(Comparator& bob)
bob.compare(item1, item2);

that will make the class use the correct virtual function. With out the ampersand, it assumes that class is of type base and uses the wrong function. (The base compare function).
 

voodoodrul

Senior member
Jul 29, 2005
521
1
81
Originally posted by: Cogman
Ok, if I'm understanding your problem correctly, You have 3 classes, a base class and two derived classes. You need each class to perform a comparison, but each has its own method of doing comparisons.

This sounds like a job for virtual functions. You should define Compare as a virtual function and then in each sub-class define it as what you need. Then, if you need to pass the class to a function of some sort, make sure that you pass it by reference or as a pointer. IE

int doStuff(Comparator& bob)
bob.compare(item1, item2);

that will make the class use the correct virtual function. With out the ampersand, it assumes that class is of type base and uses the wrong function. (The base compare function).

Thanks for the reply! I did this via a virtual function earlier, but the virtual function just allows the proper Compare() method to be called if I am allowed to set the type of the Comparator to, say PriceComparator. If I have
Comparator basicComparator = new Comparator();
Comparator priceComparator = new PriceComparator();

Then using a virtual function definition means that basicComparator would end up executing the Compare() function as defined in Comparator, whereas priceComparator would execute the Compare() defined in PriceComparator.

If I am only allowed to create objects of type Comparator, and I pretend I have no knowledge of the derived class PriceComparator, I'm not sure what to do.
 

degibson

Golden Member
Mar 21, 2008
1,389
0
0
Factory methods to the rescue!

Make a static method of class comparator called AllocateComparator(type). This function does the type-sensitive allocation and returns a pointer to a new'd object.

e.g. in C++ (sorry I'm too rusty on anything else to get it right)

class Comparator {
...
..static Comparator* AllocateComparator(Type t) {
....if(t=="price") {
......return new PriceComparator();
....}
../* ETC */
..}
};

/* Client code */
Comparator *myComparator = Comparator::AllocateComparator("price");
 

voodoodrul

Senior member
Jul 29, 2005
521
1
81
Thanks guys. I'm going to call this requirement bogus. You never use the base class to interact with its children. We would never expect Shape to know about Circle, Square, etc. We simply say Shape circle = new Circle(); Trying to make a Circle any other way will lead to serious problems. We also wouldn't try to use the base Object class to make and instance of SuperAwesomeTetrisClass. While it is an Object, we would simply grab the appropriate type somewhere from the hierarchy and say Object game = new SuperAwesomeTetrisClass;

 

Markbnj

Elite Member <br>Moderator Emeritus
Moderator
Sep 16, 2005
15,682
14
81
www.markbetz.net
I don't know about bogus, but it's probably not thought out very well. The problem, or one of them, is that the actual intelligence required to do the comparison has to be closely associated with the type(s) being compared. If you want a hierarchy of comparators with the type-specific logic in the leaf classes then you need a root type for all comparable types, and you can define a virtual method at the root that takes that root type and is implemented in the leaf classes.

That's an unnecessarily cumbersome and brittle approach in my view, since it separates the measurement logic from the definition of the type being compared, meaning both have to be evolved in lockstep from that point forward. An alternative is to define an interface IComparable, to be implemented by all types which may be compared. I like this approach because it preserves and reuses the logic of comparison, while delegating the actual measurement to the type being measured.
 

eakers

Lifer
Aug 14, 2000
12,169
2
0
I would probably use the Factory Pattern like degibson suggested. There have been many times I've had to use the base class without any knowledge of the child to perform actions but I needed to use a factory to instanciate the appropriate type and then just use virtual functions to operate on that object.

eta: http://en.wikipedia.org/wiki/Factory_method_pattern
 

voodoodrul

Senior member
Jul 29, 2005
521
1
81
Originally posted by: eakers
I would probably use the Factory Pattern like degibson suggested. There have been many times I've had to use the base class without any knowledge of the child to perform actions but I needed to use a factory to instanciate the appropriate type and then just use virtual functions to operate on that object.

eta: http://en.wikipedia.org/wiki/Factory_method_pattern

I have no problem with using factory methods, but if we stick to a convention that the base class should know nothing of the derived classes, the factory method probably should not be in the base class. In the end, that's how I'm doing it anyway.

Thanks for the input all!
 

degibson

Golden Member
Mar 21, 2008
1,389
0
0
Originally posted by: voodoodrul
I have no problem with using factory methods, but if we stick to a convention that the base class should know nothing of the derived classes, the factory method probably should not be in the base class. In the end, that's how I'm doing it anyway.

Some coders/specs/sg's take this base-class-cannot-know-about-child-classes argument to an extreme, and instead of having a static factory method in class Parent, they instead make a factory object of type ChildFactory. The namespace pollution ends up the same... just in a different file.

For my part, I think that takes OOP a little too far (I think 'object factory objects' are a little too abstract). But I do like to keep 'Child knowledge' outside of the Parent's source files (e.g., Parent.C). Hence, when I find myself making a static factory method part of class Parent, I usually implement it all by its lonesome in Parent_Factory.C instead of Parent.C.
 

ahurtt

Diamond Member
Feb 1, 2001
4,283
0
0
I've usually seen "Comparable" or "Comparator" as interfaces, not concrete classes.

One approach you could do would be to make a "Comparable" interface which defines compareTo(Object obj). Implement this interface in any class you want to give to Comparator's compare() method such that the Comparator compare method looks like compare(Comparable obj1, Comparable obj2). In java (my main language) it'd look like:

internally, each Comparable classes compareTo() method is responsible for making sure the passed in Object is of the appropriate type which should be the same type as the class implementing the compareTo(Object obj) method.
 

voodoodrul

Senior member
Jul 29, 2005
521
1
81
Originally posted by: ahurtt
I've usually seen "Comparable" or "Comparator" as interfaces, not concrete classes.

One approach you could do would be to make a "Comparable" interface which defines compareTo(Object obj). Implement this interface in any class you want to give to Comparator's compare() method such that the Comparator compare method looks like compare(Comparable obj1, Comparable obj2). In java (my main language) it'd look like:

internally, each Comparable classes compareTo() method is responsible for making sure the passed in Object is of the appropriate type which should be the same type as the class implementing the compareTo(Object obj) method.

This would be fine, except I have never seen multiple ways to compare objects implemented in IComparable. Sometimes we want to compare based on cost (data member in the object), price (data member in the object), and profit (calculated from an overridden method in the derived object class).

Can you do IComparable using multiple comparison strategies like this?
 

voodoodrul

Senior member
Jul 29, 2005
521
1
81
Originally posted by: degibson
Originally posted by: voodoodrul
I have no problem with using factory methods, but if we stick to a convention that the base class should know nothing of the derived classes, the factory method probably should not be in the base class. In the end, that's how I'm doing it anyway.

Some coders/specs/sg's take this base-class-cannot-know-about-child-classes argument to an extreme, and instead of having a static factory method in class Parent, they instead make a factory object of type ChildFactory. The namespace pollution ends up the same... just in a different file.

For my part, I think that takes OOP a little too far (I think 'object factory objects' are a little too abstract). But I do like to keep 'Child knowledge' outside of the Parent's source files (e.g., Parent.C). Hence, when I find myself making a static factory method part of class Parent, I usually implement it all by its lonesome in Parent_Factory.C instead of Parent.C.

I agree with you whole heartedly and this is how I approached it from the start. I will use your confirmation of method that I am sane.

See? I just need to find one person to agree with my position, and its all okay again. Ha. So broken.