C++ inheritance - changing the data type of a structure field

Ok this should be easy. What I have is a class for a doubly linked list with three long int fields. I want to make such a linked list in which one of the fields is a double float instead of a long int. How do I do this? My code from the .h for the doubly linked list is:

typedef struct DList
	long Vertex;
	long To;
	long Cost;
	DList* Next;
	DList* Previous;
		Next = NULL;
		Previous = NULL;
		Vertex = -1;
		To = -1;
typedef DList* DListPtr;

class DLList
	void DLList::AddANode();
	void DLList::Advance();
	void DLList::Rewind();
	void DLList::DeleteANode(DListPtr corpse);
	void DLList::PrintList();
	void DLList::PrintListBackwards();
	void DLList::RewindToHead();
	void DLList::MoveToBefore(DListPtr source, DListPtr dest);
	void DLList::MoveToAfter(DListPtr source, DListPtr dest);
	DListPtr DLList::InsertANodeBefore(DListPtr point);
	DListPtr DLList::InsertANodeAfter(DListPtr point);

	DListPtr Head, Tail, CurrentPtr;

I don’t even want to change ANY of the code other than the data type of COST. My functions don’t do anything at all that would have to change. COST is only changed from outside the class.

I think you’re going to have to change the code. Sorry.

A derived class cannot change the types of the member variables it inherits. So you can’t change Cost that way, if that’s what you were hoping for.

Nor does it do much good to derive a class and add a new member variable named Cost of type double. The implementation of DLList will still be accessing the integer variable.

So you’re going to have to rewrite something. One possible solution is to rewrite DList as a template class, with the type of Cost passed as a template parameter. For example:

template <typename TCost>
struct DList
  long  Vertex, To;
  TCost  Cost;

This allows you to defer the decision of Cost’s type until the class needs to be used. You can even have both flavors of the class instantiated: one with an integer, one with a double.

Otherwise, the simplest solution is to do precisely what you prefer not to do: change the type of Cost and correct (where necessary) the implementation of DLList. Offhand, given the relatively low number of methods, and a guess at their workings, this wouldn’t seem to be so bad.

Or is it?

I may be saying what ByteGeist is saying, but an alternative is to create a class with no cost member, lets call it DLList, then from it derive two other classes, one called maybe DLListL, with cost as a long, and one called DLLListD with cost as a double – okay these are stupid names, I don’t have enough context to make intelligent names here.

Then all the common code can live in your definition of the DLLList class, and all the specific code, the code that has to know whether cost is a double or a long, resides in the respective subclass.

DLLList might even be an abstract class, so that noone will be instantiating a DLLList with no cost member.

As Bytegeist said, member variables are additive. I believe you can inherit and add a member variable with the same name with a different type, but you’re just shadowing the name. You’ll be able to refer to the base variable with a qualified name (ie. Base::Cost). It may be better to derive two separate classes from a common type that holds the “vertex” and “to” fields.

Unless there are unusual requirements, I think it’s sort of silly to be writing a tightly bound node/list class with internal linkage. The std::list template is so much easier to use and get right. And separate iterators provide a much richer set of operations for list traversal than the single cursor embedded within the list in your proposed implementation.

But if I had to, I’d create a separate class for the linkage fields, and then use derive the data classes from it.

class DNode {
    DNode* next;
    DNode* prev;

class DDataBase : public DNode
    DDataBase(long vertex, long to)
        : vertex_(vertex),
          to_(to) {}
    ~DDataBase() {}
    long vertex;
    long to;

class DDataLong : public DDataBase
    DDataLong(long vertex, long to, long cost)
        : DDataBase(vertex, to),
          cost_(cost) {}
    ~DDataLong() {}
    long cost;

class DDataDouble : public DDataBase
    DDataLong(long vertex, long to, double cost)
        : DDataDouble(vertex, to),
          cost_(cost) {}
    ~DDataDouble() {}
    double cost;

template<typename T>
class DList {

    DNode    sentinel;

Using a template for the DDList can give you a bit of type safety, so you don’t accidently add a DDataDouble node on a DList<DDataLong>, etc.

I’ve written such a class for an high performance embedded application that justified the use of intrusive linkage. It wasn’t a trival exercise, but it worked fine. But for most applications, I prefer the simplicity of std::list.

Thanks guys! I’m interested in checking out the std::list but as it stands, I’ll put off using it for another day. It would be more trouble than it’s worth. I’ll just copy and paste the class stuff with a double instead of a long (nobody else will have to use this code anyway). It’s a bit inelegant, but whatever.

It’s not really that much trouble to use the std::list template. The standard template library (STL) is very easy to learn, and saves a lot of time by taking care of implementation details. You only have to create the record class you want a list of, and the template takes care of allocation, iteration, and things like sorting if you need that. Of course, you’ve already put time into your own implementation and you may not have time to learn the STL at the moment, but try it when you get the chance.

The STL is great, but you need to spend some time learning how to use it first.

Just in case you want to learn the STL, I found this immensely helpful.

If you’re going to rewrite the client code that uses your list then I’d recommend using std::list (with a new element struct) because of the convenience of the std container and algorithm interface.

This would also be a good introduction project (for you to learn the containers/algorithms) because you already know what you need to do with the data structure (I assume you’ll model it on the existing processing algorithms).

If you’re not rewriting the client code, then the copy & paste technique will require you to copy all of the client code as well and if it will be in use for any period of time you’ll need to synchronize changes between both copies.

I’m well aware that sometimes copy & paste is all that you’re given time for, but if this isn’t one of those times, then it would be a good time to learn new skills.

(Also after ultrafilter and Algorithm posted, I couldn’t resist putting my nick in the thread :D)

I’ll join the fray, in a highly off topic way, for three comments/reasons.

  1. Its good to know how to write basic containers and common abstract data types anyway. The STL is a wonderful boon to not having to roll your own more than once, of course. Especially when what you need is almost in the STL, but requires something that means you have to roll your own anyway. Good to learn the techniques.

  2. The STL really doesn’t necessarily help the underlying problem. The problem isn’t the container code, presumably… it’s the differences in the contained item. As already mentioned here, a common base class with an interface that is made common to both derived classes that contain the uniqueness (the one different field in each) is the way to go. (I add nothing new that hasn’t been said, here) If you want to use both such classes simultaneously in the same container, you might want to look into polymorphism and having getters/setters of that underlying different field be virtual methods.

  3. To post my sig. (I don’t have a cool nick, like np_complete.) :smiley:

I apologize, my sentences in #1 got rearranged wrong. I meant:

  1. Its good to know how to write basic containers and common abstract data types anyway. Especially when what you need is almost in the STL, but requires something that means you have to roll your own anyway. Good to learn the techniques. The STL is a wonderful boon to not having to roll your own more than once, of course. *