2

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

Martin York
  • 257,169
  • 86
  • 333
  • 562
Tri Noensie
  • 786
  • 7
  • 24
  • 2
    The reason for C++ not having a `super` keyword is probably that in C++ there is multiple inheritance. You can have several base/super classes. So you use the base class's proper type instead: `queue::push(insertMe)`. However, make sure you read the answers explaining why inheriting from STL containers probably doesn't what you want. – sbi Oct 14 '09 at 18:26
  • Have you also considered simple putting those values into a struct of their own, so you can always guarantee that the related values are added and removed together? – UncleBens Oct 14 '09 at 19:57

4 Answers4

6

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
  • 476,176
  • 80
  • 629
  • 1,111
  • Are you telling that deriving from queue is valid? – Ponting Oct 14 '09 at 18:06
  • 1
    With sufficient care, yes. I'm not sure I'd really recommend it, but there's nothing that makes it automatically invalid. – Jerry Coffin Oct 14 '09 at 18:07
  • 1
    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 Oct 14 '09 at 18:08
  • 2
    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 Oct 14 '09 at 18:25
  • 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 Oct 14 '09 at 19:43
  • 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 Oct 14 '09 at 19:44
2

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
  }
};
Community
  • 1
  • 1
Kirill V. Lyadvinsky
  • 97,037
  • 24
  • 136
  • 212
  • 1
    That's containment instead of inheritance, which might be better, but would probably need some explanation to be understood. – sbi Oct 14 '09 at 18:28
  • 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 Oct 14 '09 at 19:46
1

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
  • 976
  • 5
  • 7
  • 1
    Well, it is possible. What's impossible is to treat the resulting class as a `std::queue`. Classic _polymorphism_ doesn't work with the STL. (Compile-time polymorphism does, however.) – sbi Oct 14 '09 at 18:22
  • Yes..what I meant is you can not reroute the calls to pop() etc methods of queue using the dynamic binding. – Ponting Oct 14 '09 at 18:25
  • I don't understand the latest downvotes..is there something wrong in the answer ? – Ponting Oct 14 '09 at 18:32
  • 1
    Its not "not possible". That its not working for most use-cases doesn't change that. – Georg Fritzsche Oct 14 '09 at 20:25
  • @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 Oct 18 '09 at 12:19
1

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
  • 19,700
  • 9
  • 74
  • 90