Envision, Create, Share

Welcome to HBGames, a leading amateur game development forum and Discord server. All are welcome, and amongst our ranks you will find experts in their field from all aspects of video game design and development.

C++ Tutorials - Introduction

I said I'd do something like this before, so here I am.

I'm looking to see if anyone is interested in learning C++, I will only cover code, not any specific operating system libraries, compilers, etc. I've been to a number of talks where 50% of the topic was covering Linux/Mac/Win differences in compiling methods, so you'll have to setup your compiler yourself, but if anyone wants to learn the language, please continue reading.

If you are interested in crazy coding, check out my Object Orientated C thread where I put the C++ into C!

Introduction
C++ is my favourite language, but it has a LOT of problems. Personally; I value code legibility over speed of implementation as I enjoy writing clean and fast code, so I actually limit the features of C++ that I use.

So for the sake of readability, I will not be fully using the feature-set of C++ for these tutorials and I will try to teach at some kind of legibility standard.

The C/C++ standard I code by is my version of idSoftware's coding standards, basically I follow that guide up until the typedef examples given, I am more like this type of person:
C++:
// Define with the suffix of _type

struct myStructure_s;

enum myEnumerator_e;

int ( * MyFunctionPointer_f )( const int );

class myClass_c; // I don't use this one

 

// Typedef these as such:

typedef struct myStructure_s myStructure_t;

typedef enum myEnumerator_e myEnumerator_t

typedef int ( * MyFunctionPointer_f )( const int ) myFunctionPointer_t; // I don't use this one

typedef class myClass_c myClass_t; // I only use this with namespace forwarding without using namespace and I use it very rarely
All my typedefs are used to mask variable types.

Also, I do not use getters/setters unless it makes sense. If I want it to be read only, then I use a getter, if I want it to be write only, then I use a setter. I will not use both unless getting/setting the value requires additional processing (EG: SetFOV() may need to rebuild some 3D matrices, GetFOV() would simply return the value).

A lot of teachers enforce this one, Notch famously never cared about it, but I believe that it's importance was lost at some point and now people either do it religiously because they think they should or don't do it because they don't see the point/understand the concept.

I also enforce const-correctness, this practise is only good for readability and stopping people from breaking your code when you pass it onto the next employee, it's probably not really an issue for closed-sourced personal projects.

Okay, that's the introduction over, now for some questions.

What would you like to learn?

I will probably start with Hello World, but from there, where should I take this? C++ game tutorial? C++ 2D graphics? I don't really know so some input on what people actually want to learn would be great.

Also, the dialect for C++ is very broad.
The way most people teach it is with GNU standards, here's the C GNU standard:
C:
<div class="c" id="{CB}" style="font-family: monospace;"><ol><span style="color: #993333;">void my_function()

{

    <span style="color: #993333;">int my_variable = <span style="color: #cc66cc;">2;

}
In the standard I use it would look like this:
C:
<div class="c" id="{CB}" style="font-family: monospace;"><ol><span style="color: #993333;">void myFunction() {

    <span style="color: #993333;">const <span style="color: #993333;">int myVariable = <span style="color: #cc66cc;">2;

}
The GNU way is what I learnt and I hate it, if you don't want me to enforce the idSoftware standards and would rather I taught the GNU standard (The usual way to teach it, however I don't think it is as readable) then just say so and I'll switch for this thread.

The main thing with GNU standard is that it assumes you don't have a wide-screen monitor so it splits up lines into multiple lines, which to me looks ugly, however a lot of people don't like it when lines are so long that you need to horizontally scroll, so keep this one in mind if you'd rather I did my examples in GNU standard, but I recommend idSoftware's standard when it comes to games.
 
I actually need to learn C++ next semester for my graphics class. I'm mainly interested in the ways that good code in C++ differs from good code in, say, Java. My understanding is that C++ has a lot of idiosyncrasies and best practices that aren't immediately obvious. Also, I don't know anything about manual memory management. That said, I intend to research this on my own anyway, so don't feel obligated to write tutorials about these things if you don't feel like it.
 
Good Java code is heavy on code re-usage and strict on the coding style. If it's been done before, use the library/sources, code like everyone else so we're all on the same page and the next guy can pick up your code when they reuse it.

Good C/C++ code depends on the person, the code standards are so relaxed on C++ because it's such a massive swiss-army-knife of a language, you're not expected to use everything, whereas in Java you will have someone on your shoulder whispering disappointment that you did not use an interface or that you wrote far too much in the static {} block of a class without actually instantiating anything.

To me, good C++ code is readable. It is the messiest compiled language I've used and a lot of programmers feel obliged to use all the features even when it doesn't make sense, a class dedicated to printing out text is ridiculous when a namespace encapsulated function would be more suitable, Java would have classes for everything, but the equivalent of the namespace'd function would be a class with static methods.

Good C++ code could be full usage of the OOP approach, some C++ programmers in industry believe in the OOP approach a little too strongly, one of my lecturers at university would say "If it's not in a class, write it in C!", she didn't mean extern "C" {} the code, she literally meant make instances of classes for everything, which was totally needless.

Few people these days believe that good C++ code is fast C++ code, it's become less of an issue, but back in 1996 the Build engine in Duke3D, written in C and Assembly, was considered amazing, blazing fast, the code must be wonderful - and it is, but the code is awful to read, the entire thing is written in 1 big .C file, assembly thrown about everywhere, variables named a1, a2, a3 that hold important data and magic numbers with no explanation, but you may consider speed as good C++ code.

Using C++ for a good reason is a mark of good C++ code, Starcraft moved from C (Warcraft II) to C++ to help with the unit and building behaviour, the classes of C++ certainly helped there. Half-Life 1 has C++ written on top of the C Quake code for it's AI system, they ended up having AI that inherited different features from each other (Multi inheritance is a very strong point of C++, so you can have a class dedicated to chicken-like behaviour that inherits walk like a chicken, talk like a chicken and flap wings like birds).

What kind of good code are you expected to write?

I'll write up stuff to do with manual memory management, although I do way more of that in C than C++ so I'll start with a C approach before shoving in classes.

EDIT: Objective-C programmers write good code if their code looks like Apple's code, which I find quite funny. The code looks like a mess to me and they are always complaining about missing features, so even there it depends on what the programmer considers good code, and at my work that's code that looks like Apple's! In Java I believe Oracle's standards are the preferred.
 
I think we're really only expected to write code that works. I doubt anyone's going to be looking at the code, so it's more for my benefit, since I'll be doing a lot more C/C++ before I graduate. The performance engineering class is in C and Assembly (urk), the multithreading class is in C/C++, I think the operating systems class is in C/C++, etc. I'm much more concerned with extensibility, code reuse, readability, etc. than performance, but I guess if you don't care about performance, you're not coding in C++ in the first place. I'm very much an OO programmer, but I seem to remember hearing that C++'s OOP isn't that good or something. Can you elaborate more on that? Also, does it have features like interfaces? How does OOP in C++ differ from OOP in Java or C#?
 
C++ is just as fast as C, it's the Standard Template Library (STL) that is slow on some operating systems, the STL comes with most C++ compilers, it's like a standard set of templates that you don't have to use but it's there to help (Many, many graphics and game engines don't use it and write their own, faster versions).
It does depend on the compiler if the STL is going to be slow.

C++ classes are just as fast as the C classes in my Object Oriented C article, it's literally just calling functions in system memory which is how all programs execute.

With Objective C the classes are slower because it really takes the messaging concept to heart and parses it's method arguments as strings to the operating system's objective C runtime to decode and point it to the correct class instance, so you may have been thinking of that language.

C++'s OOP is the most powerful out of all languages due to the multi-inheritance, it blows everything out of the water with just that. There is one thing it lacks compared to other languages is lambda functions (which is a functional programming feature, not OOP), so you can't inline a function as an argument, you can fake it with some C++ compilers, but it's something you can't do.
Personally, I find that lambda functions are ugly pieces of code that breaks up the readability massively so I opt for function pointers, it breaks up the code so the inline function is completely outside the body, the down side is that you need to parse arguments to it, but even my Obj-C colleagues think it's a neat system as they managed to parse an Obj-C class as an argument of a C function, which seems very awesome even just typing about it!

The interfaces is achieved with virtual methods of a class and then you inherit that class and override the virtual methods.

In C++ the OOP approach is all optional, so you can mix procedural with OOP code, the biggest difference is the multi-inheritance.
C# is like Java and C++ mashed together, to me it's C++ with strict rules and a wall-off garden stopping you from making stupid decisions, C++ practically celebrates bad programmers and will do nothing to stop you from writing terrible code, there is no framework enforcement or anything, so it won't ask you to fill in the virtual methods with your own.

C++ also has the delete object override available which is very cool, with Java you simply assign an object to NULL and the garbage collector will eventually crawl to the object and clean it up, in C++ you do manual memory management, where you might see this as a bad thing at first, it very quickly become a powerful tool as you can call additional deconstruction commands before an object is deleted by overriding the delete method, so if the object contains other classes you can then free those classes or increment a counter of how many objects are deleted or inform your custom made garbage collector to not check this section of memory because I have deleted it myself.

That's the other big plus, operation overrides. It's the one thing the other programmers around me are jealous of, I can override the + action so it will add two vectors together when there are two vectors either side. This one is a double-edged sword, a lot of people make stupid overrides and even the STL for some reason overrides bit shift left << as a string streaming method, which was done just to copy Java's "a" + "b", but java has that problem where you must "" + var to cast a variable to a string, so you end up with that issue in C++ the moment someone overrides an operator, the crazy unexpected behaviour mostly comes from this and even idSoftware made the dumb choice to override the multiply * action of their vector class so it does the dot product of vectors, rather than, erm, multiplying them?
 
I knew about multi-inheritance already and would argue it's not a great feature, but I suppose it can be good if you don't use it in a bad way. I prefer interfaces because there's no risk of ambiguous functionality in case you have two methods with the same name, and also you don't have any mystery functionality being added to your classes elsewhere, but yeah.

You can do operator overloading in C# as well. It's extremely useful.

So what is there to know about manual memory management besides allocating and deallocating memory when objects are created and destroyed?
 

Nachos

Sponsor

This is actually really interesting for me given that I started learning Java on my own but given up after a while and always wnated to learn C++
 
The multi-inheritance comes under the tree of programmers are free to make mistakes, it's very useful and powerful but a lot of the time people are using it where it's not needed, I am yet to find another case for using it beyond AI, I even question the need for single inheritance before implementing it

Here's some manual memory management examples in C, so no classes are used in this example, it compiles fine with C++ too:
C:
<div class="c" id="{CB}" style="font-family: monospace;"><ol><span style="color: #339933;">#include <stdlib.h> // malloc, etc

<span style="color: #339933;">#include <stdio.h> // Printf

<span style="color: #339933;">#include <string.h> // memcpy

 

/*

====================

main

 

    Application entry point

    argc and argv are assigned by the operating system

    Returns an exit code for the application to indicate status

====================

*/

<span style="color: #993333;">int main( <span style="color: #993333;">int argc, <span style="color: #993333;">char ** argv ) {

    // Allocate space in RAM for 10 integers

    <span style="color: #993333;">int * <span style="color: #993333;">const numbers = ( <span style="color: #993333;">int * )malloc( <span style="color: #cc66cc;">10 * <span style="color: #993333;">sizeof( <span style="color: #993333;">int ) );

 

    <span style="color: #b1b100;">for ( <span style="color: #993333;">unsigned <span style="color: #993333;">int ii = <span style="color: #cc66cc;">0; ii < <span style="color: #cc66cc;">10; ii++ ) {

        // Fill the array with numbers 10 to 19

        numbers[ii] = ( <span style="color: #cc66cc;">10 + ii );

    }

 

    [url=http://www.opengroup.org/onlinepubs/009695399/functions/printf.html]printf[/url]( "The forth number is: %d<span style="color: #000099; font-weight: bold;">\n", numbers[<span style="color: #cc66cc;">4] ); // Should print 14

 

    // Assign a pointer that points to the address of the value 4 * sizeof( int ) into memory block "numbers"

    <span style="color: #993333;">int * <span style="color: #993333;">const forthNumber = &numbers[<span style="color: #cc66cc;">4];

 

    [url=http://www.opengroup.org/onlinepubs/009695399/functions/printf.html]printf[/url]( "The fifth number is: %d<span style="color: #000099; font-weight: bold;">\n", forthNumber[<span style="color: #cc66cc;">1] ); // Should print 15

 

    [url=http://www.opengroup.org/onlinepubs/009695399/functions/printf.html]printf[/url]( "The third number is: %d<span style="color: #000099; font-weight: bold;">\n", forthNumber[<span style="color: #cc66cc;">-1] ); // Should print 13

 

    free( numbers ); // Release the 10 numbers

    

    [url=http://www.opengroup.org/onlinepubs/009695399/functions/printf.html]printf[/url]( "The sixth number is: %d<span style="color: #000099; font-weight: bold;">\n", forthNumber[<span style="color: #cc66cc;">2] ); // Displays OS garbage because we just released this block through the other pointer (This line may even crash on some operating systems)

 

    // So we can use this to allocate entire chunks of RAM for data that we want to fast read/write

 

    <span style="color: #993333;">char * <span style="color: #993333;">const gigabyte = ( <span style="color: #993333;">char * )malloc( <span style="color: #cc66cc;">1073741824 * <span style="color: #993333;">sizeof( <span style="color: #993333;">char ) );

    // With systems that have 8-bit chars we just allocated a gigabyte of RAM just like that

    // Now we can very quickly fill it with whatever we want

 

    <span style="color: #993333;">char * <span style="color: #993333;">const myMessage = "Hello World<span style="color: #000099; font-weight: bold;">\0"; // Create a pointer to an array of characters

    <span style="color: #993333;">const <span style="color: #993333;">unsigned <span style="color: #993333;">int messageLength = strlen( myMessage ); // strlen returns the length of a string up to it's zero terminator, if there was no zero it will just keep going!

    

    // Copy our message into byte 455 of the gigabyte chunk we allocated

    memcpy( &gigabyte[<span style="color: #cc66cc;">455], myMessage, messageLength );

 

    <span style="color: #b1b100;">for ( <span style="color: #993333;">unsigned <span style="color: #993333;">int ii = <span style="color: #cc66cc;">0; ii < messageLength + <span style="color: #cc66cc;">8; ii++ ) {

        <span style="color: #993333;">const <span style="color: #993333;">int offSet = <span style="color: #cc66cc;">451 + ii;

        <span style="color: #993333;">const <span style="color: #993333;">char value = gigabyte[offSet];

        [url=http://www.opengroup.org/onlinepubs/009695399/functions/printf.html]printf[/url]( "address 0x%p contains %c<span style="color: #000099; font-weight: bold;">\n", &gigabyte[offSet], value );

    }

 

    free( gigabyte ); // Release the gigabyte of memory

 

    <span style="color: #b1b100;">return <span style="color: #cc66cc;">0;

}

I added break points around the the line where that gigabyte of memory was allocated, this is what Windows 7's task manager reported about my program's memory usage before and after the allocation:
gigabyte_before_after.png


Doing this behavior is useful when you're doing very low level or very high performance stuff like game engine or network code. My networking engine handles all the packets with the first few bytes of the packets describing how much memory it wants to allocate before being read, if the contents inside the packet does not match the amount stated then it gets thrown away as a malformed/malicious/hacked data packet. Once it's in memory, I can just point to known locations in it and extract my data as pointers to the correct numbers.

I can also split a 32 bit number into byte chunks without using bit-wise operators:
C:
<div class="c" id="{CB}" style="font-family: monospace;"><ol><span style="color: #993333;">const <span style="color: #993333;">int integerNumber = <span style="color: #cc66cc;">123456;

    <span style="color: #993333;">unsigned <span style="color: #993333;">char bytes[<span style="color: #cc66cc;">4]; /* Assume the sizeof( int ) == 4 bytes */

    

    <span style="color: #b1b100;">for ( <span style="color: #993333;">unsigned <span style="color: #993333;">int ii = <span style="color: #cc66cc;">0; ii < <span style="color: #cc66cc;">4; ii++ ) {

        bytes[ii] = ( ( <span style="color: #993333;">char * )&integerNumber )[ii]; /* Cast the address of the integer to a character pointer, then get the address of the item offset ii * sizeof( char ) in memory */

    }

    

    /* So now we have an array of the integer's bytes */

    <span style="color: #b1b100;">for ( <span style="color: #993333;">unsigned <span style="color: #993333;">int ii = <span style="color: #cc66cc;">0; ii < <span style="color: #cc66cc;">4; ii++ ) {

        [url=http://www.opengroup.org/onlinepubs/009695399/functions/printf.html]printf[/url]( "byte[%d] : %d<span style="color: #000099; font-weight: bold;">\n", ii, bytes[ii] ); /* Output the bytes as numbers */

    }
The output should be this:
byte[0] : 64
byte[1] : 226
byte[2] : 1
byte[3] : 0
Already you can see we can compress this chunk by stripping off byte[3]

Converted to hex that's:
40 E2 01 00
Flip it for the endianness of the CPU
00 01 E2 40
And then convert that to decimal
123456
 
I've written up my coding standards based on the idSoftware coding standards.
xilef CPP code standards.html
If you want to write readable code, then have a look. It's mostly derived from my C coding standards (Which I have as a separate document, if anyone wants to take a look then ask).

I'm going to consider this an open standard, so if you have anything to add/criticise/comment/expand on then please say so and I'll make amendments.

Tutorial 1: Hello Classes

In C/C++ a program is generally split between multiple files, the only way to link the program together is with header files, which inserts the contents of a file into another file. This works because the compiler will read the source top-bottom in order of compilation and will remember which functions/classes/objects/types/etc have been defined, when one of those is referenced the compiler will look into what it has already covered and then pull the thing out.
Newer languages will scan the entire source for definitions before compiling the program and linking the definitions in.

So in all these examples I'll write a header and an implementation (The source that actually gets compiled after the header contents is copied in).

Hello World with classes

Header [MessagePrinter.h]
C++:
<span style="color: #339900;">#ifndef __MESSAGE_PRINTER_H__

<span style="color: #339900;">#define __MESSAGE_PRINTER_H__

 

// Our class for printing a message to the command line

// A class is like a type that contains data and methods for manipulating the data

// We make a new class type called xiMessagePrinter

class xiMessagePrinter {

// Anything inside the public: section can be seen by other classes

// In short, if you don't want people messing with this class' message, don't put it in public

public:

            xiMessagePrinter( const char * const inputMessage ); // Constructor

    void    PrintMessage() const; // const denotes that this method will not modify any data inside the class, we only read message

// Anything in the private section is only visible by this class, we put data here that we don't want other parts of the program accessing

private:

    char    message[<span style="color: #0000dd;">128]; // A message that is limited to 128 characters

};

 

<span style="color: #339900;">#endif

Implementation [MessagePrinter.cpp]
C++:
<span style="color: #339900;">#include "MessagePrinter.h"

<span style="color: #339900;">#include <string.h> // strcpy

<span style="color: #339900;">#include <stdio.h> // printf

 

// When we define the actions of the class in the implementation we use className:: to tell the compiler that this function belongs to that class

xiMessagePrinter::xiMessagePrinter( const char * const inputMessage ) {

    // Copy the first 128 characters of the inputMessage into the class' message attribute

    <span style="color: #0000dd;">strcpy( message, inputMessage, <span style="color: #0000dd;">128 );

}

 

void xiMessagePrinter::PrintMessage() const {

    // Print the contents of this class' message on the console

    <span style="color: #0000dd;">printf( <span style="color: #666666;">"%s<span style="color: #666666; font-weight: bold;">\n", message );

}

Implementation [main.cpp]
C++:
<span style="color: #339900;">#include "MessagePrinter.h"

 

int main( int argc, char ** argv ) {

    // Make an instance of messagePrinter with the message "Hello World"

    // The "new" key word acts like a malloc() and allocates memory with the sizeof( xiMessagePrinter )

    xiMessagePrinter * const messagePrinter = <span style="color: #0000dd;">new xiMessagePrinter( <span style="color: #666666;">"Hello World" );

    // Display the class's message attribute on the console

    messagePrinter->PrintMessage();

 

    // Make a new instance of the class with the message "Hi hi hi"

    xiMessagePrinter * const messageHihihi = <span style="color: #0000dd;">new xiMessagePrinter( <span style="color: #666666;">"Hi hi hi" );

    messageHihihi->PrintMessage(); // Print once

    messageHihihi->PrintMessage(); // Print twice

 

    // Free up the memory of the two objects, this is like calling free() in C

    <span style="color: #0000dd;">delete( messagePrinter );

    <span style="color: #0000dd;">delete( messageHihihi );

 

    return <span style="color: #0000dd;">0; // End the application, tell the operating system that we have ended with exit code 0

}
I haven't tested any of the above code, so copy/paste it, compile it and run it from the command line to see what it does.

If it doesn't compile, post with details of the error and I'll see if I can fix the code.

What did we just do?
We made a new class in a header file, defined the methods of the class in the implementation file (We define the methods in implementation so any other sources that include the file won't be redefining the methods by accident).
We then made main.cpp with our entry point, included the class's H file, made two different instances of that class and printed out the data we added to it on the construction.

Keep in mind that printf and strcpy are C functions, a lot of people will be upset if you use C functions in a C++ program, however I personally find printf() makes more sense than not-bit-shifting some not-bits using a bit-shift of an iostream. Most computer games actually use their own version of printf, so it's not unusual to avoid the STL in favour of C-like functions in C++ products.

Experiment Task:
Add a second private variable into the class called messageTwo and add a function that assigns the variable with a CString, then add a second method to print it and test it out in the main function.
 

Thank you for viewing

HBGames is a leading amateur video game development forum and Discord server open to all ability levels. Feel free to have a nosey around!

Discord

Join our growing and active Discord server to discuss all aspects of game making in a relaxed environment. Join Us

Content

  • Our Games
  • Games in Development
  • Emoji by Twemoji.
    Top