CS 216 Quick and Dirty C++ Tutorial

This is more of a conceptual tutorial than instructions on how to write your C++ programs. The point of this is to help you out when you are fuzzy on topics and so you're having trouble using them because you don't know how they work. Let me say right here at the top that I do not have a lot of experience with Java so don't expect extensive details about how syntax in C++ differs from Java. I'm trying to write this from the perspective of a Java programmer but I don't know enough about how Java handles things to do that well.

There is some code that I wrote to illustrate these topics but it's pretty rough. As we go through the labs I'll see if I can remember to add useful functions and a description of what each one does and how it should work to this page as well

Code is available here. You'll have to compile and build it. There are definitely compile warnings from the mismatch of types but it should compile and run.

Dave Evans has links to some C tutorials from CS216 last semester. Note that these are on C, not C++, and C does not have objects so they may not be helpful to you since you are used to programming in Java where everything is an object. They are here.

Garbage Collection

As you are all aware by now one of the big differences between Java and C++ is C++ doesn't have managed memory. What does that mean exactly? Well, whenever a variable or object in C++ goes out of scope the destructor is called to reclaim the memory. However, the destructor for pointers does not call the destructor on the object that it points to so unless you explicitly delete that object it will be left dangling in memory and that memory will not be reclaimed until the program exits and the operating system's garbage collection routine comes and reclaims it.

There's an example of this in the code included with this tutorial.

When do you need to use delete and new

The keyword new dynamically allocates memory for an object from the heap. It returns a pointer to that object, so whenever you use new it should be like:

Object *ptr = new Object();

You must use the constructor although some compilers are smart enough to call the constructor if you just say Object *ptr = new Object;
When you do this you now don't have an object that can go out of scope because it's not explicity referenced by a variable. Basically, what you need to do is to use the delete keyword on the pointer before it goes out of scope.

The lesson from this: if you use new then you have to use delete as well.

#include

The basics of includes are that #include <> tells C++ to look in it's standard libraries and #include "" tells it that it is looking for a user defined file located in the project.

However, it's not quite that simple. Some of you will have seen errors about files being included too many times. This only happens with user defined files and it's because you include the file in two or more files and have not used #ifndef SOMEFILENAME #define SOMEFILENAME *your code* #endif What this does is check the symbols and if it finds SOMEFILENAME it skips the code. If it doesn't find it, then it adds it and includes the file. All of the STL files have this which is why you never get the errors there. It's always a good idea to put this in your header files to save you some headaches later.

Pointers

Check out the code I've included. There's a function in there to go through what pointers can do and how to use them.

Here's an excerpt from the code. Hopefully it will make sense.

        input: This is our test string
        &input: 0012FDDC
        *(&input): This is our test string
        strptr: 0012FDDc
        *strptr: This is our test string
        &(*strptr): 0012FDDC
        input.length(): 23
        strptr->length(): 23
        (*strptr).length(): 23
        

Using Const

Const is used in many different ways.

Constructors, Destructors, Copy Constructors

The constructor is automatically called when you declare an object from a class. i.e. List l; calls List(). The purpose of the constructor is to initialize your class. Remember that in C++ variables are not automatically initialized (unlike in Java) so the constructor should set up your object. i.e. when you did the list you had to take the head and tail pointers and creating nodes for them, point those nodes at each other and initialize the size of the list. Until you did that your object wasn't actually a list, it was just two pointers, an int and some functions you could call on those. The default constructor will just allocate memory for the object and create the variables in that object.

The copy constructor is used to create a new object and initialize it to something. The code is probably going to be similar to the constructor but different because it's doing more than setting your object up to be empty. You can't just call the constructor in the copy constructor because the object has already been created when the copy constructor is called and calling the constructor would create another new object.

The destructor is called when your object goes out of scope. As we saw in the section on garbage collection C++ will not reclaim memory that is pointed to by a pointer when it goes out of scope. So what your destructor needs to do is take care of anything that your pointers are pointing at that is no longer needed. If you don't have objects pointed at then the default destructor (which just calls the destructors on the elements in your object) will probably work ok.

Operator Overloading

Why do we need to overload operators? If you write your own object C++ has no idea what it means for that object to equal another. Obviously, some parts can be equal while others should be different. i.e. List a == List b if the elements in a and b match and are in the same order. We definitely don't want the head and tail pointers to be the same.

You can overload any operator that you want. Here's the link to the MSDN pages on operating overloading. Here's another tutorial

The syntax for operator overloading depends on the operator. Some examples are
bool operator==(const object &a); (same for <, <=, >, >=, !=)
object & operator=(const object& a);
Check out the stuff on passing by value vs reference to explain why we have & in there.

Passing by Reference vs Passing by Value

There is a section in your text book that deals with passing by reference vs passing by value and I'd recommend you read that as well if you haven't yet.

Passing by Value

int SomeFunction(int someInt);

a is passed by value here. What C++ does in this case is create a new int called someInt and copy the value passed to it. This integer is scoped locally to the function. Sounds pretty good right? We can't mess up the variable outside the function and who cares if we declared an extra integer.
The integer case is alright, we're perfectly happy passing integers by value. What happens if we try to pass a larger object by value? It starts to take a lot more work to pass objects by value when they are larger both in terms of memory and because their copy constructor must be called.
Also, think about what happens if you are trying to overload your = operator and you pass it the object you want to copy by value. Now the = operator is getting called just to get into the operator= function with the values. You can see this would be a bad thing because now it will recursively call itself.
That being said, passing by value isn't bad, it should just be used judiciously.

Passing by Reference

int SomeFunction(int &someInt);

someInt is now being passed by reference. We just said this was a bit silly because passing ints by value is fine but we'll ignore that for consistency. Passing by reference means that you give the function the memory address of the object that you are passing it instead of the object itself. As we saw in the pointer section &someInt is the memory address so if we try to use someInt while in someFunction then we're just dealing with the actual object and you don't need to do anything special. Pretty cool eh? The one thing you have to watch out when passing by reference is that if you make a change to the object you are changing the original, not a copy so make sure you aren't destroying anything when using this method.

Basically, passing by value and passing by reference don't change how you deal with the object once you are inside the function but they can make a big difference in performance of your program. Also, passing by reference is occasionally vital as you can't write some functions when passing by value.

Input and Output

These are pretty basic. For screen input and output you'll have to include iostream in your file and add using namespace std. File input and outputs are done with fstream.

On the screen

To the screen is cout <<. If you want to cout a string it's cout <<"This is a string"; You can put anything inside cout that returns a value and have it cout that. i.e. cout << x*y; works just fine. You have two options for new lines. One is cout << endl; and the other is cout << "\n";

Input is handled by cin. Some of you also discovered that getline gets input from the keyboard as well. cin >> someVariable will read from the keyboard input stream till it gets to white space and then stop. getline(cin, 100) will get you 100 characters from the keyboard regardless of white space. You can probably see where both of these are useful. getline is useful for getting strings including whitespace and cin is great for inputting a bunch of values at once. To do this you'll probably want to have a while loop on the input so you can continue to fetch the rest of the strings from the input buffer.

In a file

Make sure you have fstream included. File inputs are slightly different. You'll need to declare variables of type ifstream (input from a file) and ofstream (output from a file). Here's a page summarizing C++ input and output using both the screen and a file.

Templates

We are not expecting you to write any templated code! We may provide you with code that is written using templates but you will primarily just need to know how to use a templated class. vector is one such thing and the difference is when you declare a vector you must also say what it is a vector of. i.e.

        vector<int> vector1;
        vector<char> vector2;
        vector<float> vector2;
        
are all valid declarations.
The brief rundown of what templates are is that they are data structures that can contain various types of data. It's called a template because you write the class around an Object data type and then specify what Object means when you declare the class.
I checked with Dr Co and the official word is that you should understand enough about templates to write code that uses them.