chevron_left chevron_right
Login Register invert_colors photo_library


Stay updated and chat with others! - Join the Discord!
Thread Rating:
  • 0 Vote(s) - 0 Average


Tutorial [C++] Building a template stack class filter_list
Author
Message
[C++] Building a template stack class #1
Okay, so you have all read my two stack classes before. In case you havent:

Building your first stack (read this one first)
Building a C++ stack class

Now, this one will be a little tricky. Previously we have used integers as our data type, which in my eyes is a little limiting. So, for this one we will let YOU choose what data type YOU want, WHEN YOU WANT TO USE IT! We accomplish this by using templates.

I will give you a basic understanding of templates (the features we will use) as this tutorial progresses, don't worry if you don't completely understand it, it should be simple.



Okay, so let me just throw some code at you before I break it down. Here is our basic class definition:

Code:
template <class custom_type>
class myStack
{
private:
     custom_type *data;
     int sp;
public:
     myStack(int size);
     ~myStack();
     void push(custom_type &insert_object);
     custom_type pop();
     bool isEmpty();
     int count();
};

Alright. Line by line breakdown: go

Code:
template <class custom_type>
class myStack

this defines myStack as a template class
Well, what does that mean?
It means that the class can take a number of different forms, and we just create a template for it to do so. When we define our stack, we can specify what type we want to put in, for example:
  • int
  • float
  • char
  • even myStack classes!
  • and just about EVERYTHING else that stores data

well, what does this mean?
Code:
<class custom_type>
That simply defines a type that we can use to write our class. Every instance of custom_type is replaced at compile time with whatever type we want to use for that specific instance.
For those of you who know C, consider it a #define, except we can redefine what it means without a bunch of hacky garbage.

There really isn't a whole lot more after that, except this function has changed:
Code:
void push(custom_type &insert_object);
Why did we add the & in there?
Simple: because we aren't dealing with built-in types. ALL ABSTRACT TYPES MUST BE PASSED BY REFERENCE, per C++ spec. This won't affect our code at all. Actually, it will be almost IDENTICAL to the last C++ stack tutorial.
This will be commented. Here is the whole thing:

oh wait! forgot to say one thing
Since this is a template class, all of the code MUST be in the header file (and I ABSOLUTELY hate this), so I will make it REALLY simple, and even put it inside the class definition.

Code:
template <class custom_type> //define our class as a template with custom_type
class myStack
{
private:
     custom_type *data; //create our storage
     int sp; //this hasn't changed from the first two
public:
     myStack(int size)
     {
          if (size < 1) return; //programmer is an imbicile
          data = new custom_type[size]; //define it as the decided type
          sp = 0;
     }
     ~myStack() //I moved the destructor to the top, I like it here better
     {
          delete data;
     }
     void push(custom_type &insert_object)
     {
          data[sp++] = insert_object;
          //note, this WILL fail if the class does not have a copy constructor.
          //well, not fail, but it won't always work the way you want it to
     }
     custom_type pop()
     {
          return data[--sp];
     }
     bool isEmpty()
     {
          return (sp == 0);
     }
     int count()
     {
          return sp; //we won't do this with variable type stacks, I promise.
     }
};

Now, that was VERY simple. I did not go into the drawn out version of the functions, you can find those in the "creating a C++ stack class" link/tutorial at the top of this thread.



USING it, however is NOT as simple. If you are new to templates/have never seen them before, this may come difficult to you (because we don't have a whole lot to work off of here) but I will try and help.

Code:
#include "myStack.h"
#include <iostream> //so we can put them on the screen this time

using std::cout; //so we can just call it cout
using std::endl; //so we can just call it endl

/* some people like to just write
* using namespace std;
* whatever your preference is
*/

int main()
{
     myStack stack_int<int>(5);
     /* now, this looks funky, lets break it down here.
      * myStack stack_int, now that is the same as before, but usually
      * we put the size right after that. In this case, we have to specify
      * the type of stack. remember that funky <class custom_type> thing?
      * well, this is what we are setting when we do <int>. Basically, the
      * compiler replaces custom_type with int in all cases for us. */
     myStack stack_char<char>(14);

     //Now, the same as before
     stack_int.push(4);
     stack_int.push(3);
     stack_int.push(2);
     stack_int.push(1);

     //now, we can make a hello world program! remember, it goes in backwards!
     stack_char.push('\n');
     stack_char.push('d');
     stack_char.push('l');
     stack_char.push('r');
     stack_char.push('o');
     stack_char.push('W');
     stack_char.push(' ');
     stack_char.push('o');
     stack_char.push('l');
     stack_char.push('l');
     stack_char.push('e');
     stack_char.push('H');

     //and, display them!
     while (!stack_char.isEmpty())
          cout << stack_char.pop();
     while (!stack_int.isEmpty())
          cout << stack_int.pop();
     cout << endl;

     return 0;
}

So, there you have it! Compile it and run it. Output should look like so:
Code:
Hello World
1234

Who wants to see one that we can do this:

Code:
myStack stk(5);
stk.push("abcdef");
stk.push(4);
stk.push('a');
stk.push(3.14);

Leave a comment if you want to see how to make variable type stacks (thats what REAL system stacks are)

[+] 1 user Likes phyrrus9's post
Reply

RE: [C++] Building a template stack class #2
There's no system hacks involved in adding abstract temples to a container, it involves principles of design in terms of features of the language. Why you would want to use something like this?--Who knows, because there's not too many cases where it can be of benefit, and to retrieve the exact type you're going to have to cast or do some conversion anyways to get data out of the container because C++ still requires a variable's type to be known. Actually, there's a few libraries, boost::any as one of them, which makes use of this quite successfully too. However, to get to that level of type safety and reliability for properly storing different datatypes and furthermore if you allow operations between 2 different types involves much more complexity; a number of proxies, expression templates, layers upon layers of perfect forwarding, and of which would devolve into template chaos.

As I mentioned before too:
Code:
if (size < 1) return; //programmer is an imbicile

You should NEVER do this, you should actually be throwing an exception or something here because the constructor can't do it's job if you simply return, and the class object remains usable even in an invalid state because of uninitialized pointers.

Reply






Users browsing this thread: 1 Guest(s)