You are here:

C++/struct and class

Advertisement


Question
I know how to program with java and decided to learn c++. When i did some reading on c++ i came across structs. Structs to me seem to be the same as a class. what is the difference between a struct and a class? Also when you pass an argument to a method does it make a copy of the object and send the copy or does it pass by reference like java?

Answer
Hi, Jeremy.

Going from Java to C++ is mostly an easy prospect, but there are indeed some... peculiarities... that you will encounter.  Structs are one of these.

Structs are holdovers from C.  In C, classes do not exist, but structs are present simply as containers for numerous variables.  "Object-oriented" programming in C was handled simply by creating structs and functions intended to operate with these structs.  There is no inheritance, no encapsulation.  Just raw data that you pretend not to be able to manipulate manually.

In C++, though, classes came into being.  Classes allow for encapsulation, inheritance, abstraction, etc.  However, C++ being a language built on top of C, the struct could not simply be tossed aside.  So, the struct evolved into something else.  In large part, structs are still treated in C++ as they were in C: simply a collection of variables.  However, in reality, a struct and a class are the same thing in C++ with a few rule changes:

- In a struct, members and functions are public by default, whereas in a class, members and variables are private by default.
- In a struct, inheritance is public by default, whereas in a class, inheritance is private by default.

Basically, in C++, struct and class are identical, just their default access rules change.  Structs fully implement inheritance, encapsulation (if you declare some things to be private), etc.  Generally, though, if you want to do all of that, you'd use the class keyword.  Structs are still pretty much relegated to data collections, though it is somewhat common for a constructor/destructor to be written for a struct.

As for arguments passed to functions, they are passed by value by default.  It is possible to pass by reference or by pointer, but you must explicitly declare them to be handled in such a manner.  Consider the following:

   void myFunc1(MyClass _input);
   void myFunc2(MyClass* _input);
   void myFunc3(MyClass& _input);

The myFunc1 function takes a variable of type MyClass, which copies the entirety of the MyClass data to the stack before entering the function.  The myFunc2 function takes a variable of type MyClass pointer.  A pointer is generally 4 bytes (on 32-bit systems).  The pointer is the only data copied to the stack in this case.  The function myFunc3 takes a variable of type MyClass reference.  A reference, like a pointer, is generally 4 bytes.  Again, this is the only data copied to the stack in this case.

The differences between pointers and references are subtle.  They can (mostly) be used interchangeably, but each has its specific properties.  First, a pointer must be dereferenced before it can be used.  A reference can be used as is.  Second, a pointer may be NULL, whereas a reference *must* contain data.  Third, a reference cannot be changed, whereas a pointer can be.  I'll demonstrate each of these quickly:

   // assume these are properly initialized
   int& intRef;
   int* intPtr;

   intRef = 5;
   *intPtr = 5;

You can see above that the reference is used just as if it were a raw int.  No special magic needed to play with it.  The pointer, though, requires you to dereference it (with the * operator).  Pointers and references to objects are also interesting:

   // assume these are properly initialized
   MyClass& classRef;
   MyClass* classPtr;

   classRef.doSomething();
   classPtr->doSomething();
   (*classPtr).doSomething();

You'll notice that the syntax for calling a function on a pointer is different than that of a reference.  A reference uses the standard . operator, just as if it were a regular object of MyClass type.  The pointer, though, uses a special operator, the -> operator.  I've also demonstrated that you can actually use the * operator in combination with the standard . operator.

Because a pointer can point to NULL (0 is not a valid memory address), you can use pointers to indicate failure conditions or to indicate that some data is not desired.  References have to contain valid data, so they cannot be used in the same manner.  However, this also means that you really ought to check that a pointer is valid before using it, whereas you don't need to do this with a reference:

   int* randomFunc(int* varA, int& varB, int* outA)
   {
       // If the user did not provide varA, we cannot continue.
       if (!varA)
         return NULL;

       // multiply varA and varB
       int blah = *varA * varB;

       // If the user specified outA, we'll store the square of blah
       if (outA)
         *outA = blah * blah;

       return blah;
   }

Now, the above function is pretty useless, but it at least demonstrates how some things would work.  Notice that it is possible to return NULL, since the return value is a pointer.  The caller can check for a NULL value and know that the function failed.  Notice also that varB is used without bothering to see if it's been provided, because we know it's a good value since it's a reference.  Finally, notice how we can optionally pass back another value using the pointer outA as a method of output.  If the pointer is not provided, then the square simply isn't stored.

Finally, a reference cannot change, whereas a pointer can.  What I mean by this is that, while the data pointed to by either type can change at any time, the reference always points at the same memory address whereas a pointer can point to different memory addresses:

   // assume these are properly initialized
   int& intRef;
   int* intPtr;

   // here we set the data pointed to by each variable to 5
   intRef = 5;
   *intPtr = 5;

   // here we actually change where the intPtr variable points to, without changing
   // the data at its currently-pointed-to location
   intPtr = 0xbaadf00d;

You can see that, without provided the dereference on the pointer, you are changing the address that the pointer points to instead of changing the data at the location pointed to by the pointer.  Now, you wouldn't want to go about setting the address a pointer all willy-nilly like I did there with the baadf00d thing, but it's incredibly handy to be able to change where a pointer points.  Pointer arithmetic is a wonderful, wonderful thing that is useful in many varied circumstances.

OK, I hope I answered your questions satisfactorily and without too much information overload.  If you have any further questions, do not hesitate to ask.

C++

All Answers


Answers by Expert:


Ask Experts

Volunteer


Joseph Moore

Expertise

I've been programming in one form or another since my brother taught me BASIC when I was 6. I've been programing professionally since I was 20, first web development with HTML, JS, DHTML, CSS, etc., then I became a video game developer, writing code in C, C++, C#, SQL, assembly, and various scripting languages. I've even written my own scripting languages, custom designed for the games I was making. I also dabble in Java, PHP, and Perl. I've worked on pretty much every aspect of game development, including graphics, audio, gameplay, tool, UI, input, animation, and physics.

Experience

I've been writing C++ code for 12 years, both on my own in my spare time and professionally.

Organizations
IGDA

Education/Credentials
Bachelor of Science in Game Design and Development, Full Sail University, Winter Park, FL

Awards and Honors
Salutatorian and Advanced Achiever Awards at Full Sail; Independent Games Festival Student Showcase winner, 2004; Featured article on Gamasutra about an experimental game developed in 2004

©2016 About.com. All rights reserved.