views:

417

answers:

4

I'm creating a new class that inherits queue from the STL library. The only addition to the class is a vector. This vector will have the same size of the queue and it will store some integer values that will correspond to each objects in the queue.

Now, I want to override pop() and push(), but I simply want to add more functionality to the parent's class methods.

ex. When pop() is called on the queue object, I also want pop an object from the vector. When push() is called on the queue object, I also want insert a new object into the vector.

How do I do that???

#include <iostream>
#include <iostream>
#include <queue>
#include <vector>

using namespace std;

template <typename type>
class CPU_Q : public queue<type>
{

  public:
    vector<int>  CPU_TIME;

    void increaseTime()
    {
      for(int ndx = 0; ndx < CPU_TIME.size(); ndx++)
      {
        CPU_TIME[ndx]++;
      }
    }

  void push(type insertMe)
  {
    //This is what I want to do
    super::push(); // or queue::push(); maybe?
    CPU_TIME.push_back(0);
  }
  void pop()
  {
    //Something very similar to push()
  }
}

Many Many thanks in advance

-Tri

+1  A: 

Simple answer is that it is not possible. STL container classes are not designed to be inherited. Their destructor is not virtual to start. If you really want to do something like this then write a new class which 'contains' the queue and vector , and use this class everywhere. BTW as a side note, there is no super keyword in C++ unlike Java. If you want to call base class method use BaseClassName::methodName();

Ponting
Well, it is possible. What's impossible is to treat the resulting class as a `std::queue<T>`. Classic _polymorphism_ doesn't work with the STL. (Compile-time polymorphism does, however.)
sbi
Yes..what I meant is you can not reroute the calls to pop() etc methods of queue using the dynamic binding.
Ponting
I don't understand the latest downvotes..is there something wrong in the answer ?
Ponting
Its not "not possible". That its not working for most use-cases doesn't change that.
Georg Fritzsche
@gf: That "most use-cases" seems suspicious to me. For me, I usually don't pass around containers at all. I only pass around iterators. Also, _if_ you pass around containers, why limit yourself to `std::queue`? Just make this a template argument and any other container providing the needed interface will do, too. All these cases work with containers inheriting from `std::queue`, even if they override any functions. The only thing not working is dynamic polymorphism.
sbi
+4  A: 

You asked about:

void push(type insertMe){
      //This is what I want to do
      super::push(); // or queue::push(); maybe?
      CPU_TIME.push_back(0);
}

That would be more like:

void push(type insertMe) { 
   queue<type>::push(insertMe);
   CPU_TIME.push_back(0);
}

Except you probably want to accept the parameter by const reference:

void push(type const &insertme) { 
    queue<type>::push(insertMe);
    CPU_TIME.push_back(0);
}

That said, the standard container classes aren't really designed for inheritance (e.g. they don't have a virtual dtors), so you'll have to be careful with this -- e.g. when you destroy it, you'll need the static type to be the derived type; you'll get undefined behavior if (for example) you destroy one via a pointer to the base class.

Jerry Coffin
Are you telling that deriving from queue is valid?
Ponting
With sufficient care, yes. I'm not sure I'd really recommend it, but there's nothing that makes it automatically invalid.
Jerry Coffin
Deriving from queue is certainly *not* valid, but it's not "not possible" either. I'd recommend to keep the queue as an instance variable and forward any push()/pop() calls.
Rüdiger Hanke
I suppose that depends on what you mean by "certainly not valid". It's "valid" to the extent that any properly function C++ compiler is obliged to accept the code. From his description, it's probably even "valid" from a design viewpoint -- he doesn't show enough to say with absolute certainty, but you can probably substitute his derived class essentially anywhere a queue is allowed (the sole obvious exception being something that destroys the queue via a pointer).
Jerry Coffin
actually both queue and stack (the adapter classes) have a protected member variable `c`. this means that they **can** be safely inherited from. It is just very rarely needed.
Evan Teran
However, the best approach to inheriting from these 2 classes is to **not** try to overload functions, but instead to add new functions. Which would always be a safe operation and always gives well defined behavior.
Evan Teran
+1  A: 

Unless your new class has a is-a relationship with std::queue, I would strongly consider encapsulating the queue and vector, and providing methods that forward to the appropriate std::queue/std::vector methods, in the order you want them to be called.

Also, if you want this new class to be compatible with standard algorithms, you will have to implement a begin() and end() method that return an iterator type capable of walking your data structure; you may be able to use the existing methods on std::queue/std::vector to accomplish this though.

Steve Guidi
+1  A: 

STL queue class in not intended to be extended using inheritance. Look here for more information on that. Besides that std::queue has more than one template argument. Instead of inheriting you could just use std::queue as a member of your template class CPU_Q as follows:

template<typename T>
class CPU_Q
{
  std::queue<T> q;
public:
  void push( T val ) 
  { 
    q.push( val );
    // additional work
  }
};
Kirill V. Lyadvinsky
That's containment instead of inheritance, which might be better, but would probably need some explanation to be understood.
sbi
Note: both `queue` and `stack` have a protected member. This implies that there is a circumstance which inheritance makes sense. However, I still would agree that composition is preferred.
Evan Teran