C++ Programming/Structures

From Wikibooks, open books for an open world
Jump to: navigation, search

Structures[edit]

A simple implementation of the object paradigm from (OOP) that holds collections of data records (also known as compound values or set). A struct is like a class except for the default access (class has default access of private, struct has default access of public). C++ also guarantees that a struct that only contains C types is equivalent to the same C struct thus allowing access to legacy C functions, it can (but may not) also have constructors (and must have them, if a templated class is used inside a struct), as with Classes the compiler implicitly-declares a destructor if the struct doesn’t have a user-declared destructor. Structures will also allow Operator Overloading.

A struct is defined by:

struct myStructType /*: inheritances */ {
public: 
 // public members
protected:
 // protected members
private:
 // private members
} myStructName;

Because it is not supported in C, it is uncommon to have structs in C++ using inheritances even though they are supported just like in classes. The more distinctive aspect is that structs can have two identities one is in reference to the type and another to the specific object. The public access label can sometimes be ignored since the default state of struct for member functions and fields is public.

An object of type myStructType (case-sensitive) is declared using:

 myStructType obj1;


Note:
From a technical viewpoint, a struct and a class are practically the same thing. A struct can be used anywhere a class can be and vice-versa, the only technical difference is that class members default to private and struct members default to public. Structs can be made to behave like classes simply by putting in the keyword private at the beginning of the struct. Other than that it is mostly a difference regarding convention and programming design, often an indication of a conversion from a C language source code or even used as an improper implicit indication that the structure will not be inherited or will not have function members (this use should be avoided and never assumed).

Why should you Use Structs, Not Classes?

Older programmer languages used a similar type called Record (i.e.: COBOL, FORTRAN) this was implemented in C as the struct keyword. And so C++ uses structs to comply with this C's heritage (the code and the programmers). Structs are simpler to be managed by the programmer and the compiler. One should use a struct for POD (PlainOldData) types that have no methods and whose data members are all public. struct may be used more efficiently in situations that default to public inheritance (which is the most common kind) and where public access (which is what you want if you list the public interface first) is the intended effect. Using a class, you typically have to insert the keyword public in two places, for no real advantage. In the end it's just a matter of convention, which programmers should be able to get used to.

Point objects 

As a simple example of a compound structure, consider the concept of a mathematical point. At one level, a point is two numbers (coordinates) that we treat collectively as a single object. In mathematical notation, points are often written in parentheses, with a comma separating the coordinates. For example, (0, 0) indicates the origin, and (x, y) indicates the point x units to the right and y units up from the origin.

The natural way to represent a point is using two doubles. The structure or struct is one of the solutions to group these two values into a compound object.

// A struct definition:
 struct Point { 
   double x, y; };

This definition indicates that this structure contains two members, named x and y. These members are also called instance variables, for reasons I will explain a little later.

It is a common error to leave off the semi-colon at the end of a structure definition. It might seem odd to put a semi-colon after a squiggly-brace, but you'll get used to it. This syntax is in place to allow the programmer the facility to create an instance[s] of the struct when it is defined.

Once you have defined the new structure, you can create variables with that type:

struct Point blank; 
blank.x = 3.0; 
blank.y = 4.0;

The first line is a conventional variable declaration: blank has type Point. The next two lines initialize the instance variables of the structure. The "dot notation" used here is similar to the syntax for invoking a function on an object, as in fruit.length(). Of course, one difference is that function names are always followed by an argument list, even if it is empty.

As usual, the name of the variable blank appears outside the box and its value appears inside the box. In this case, that value is a compound object with two named instance variables.

Accessing instance variables 

You can read the values of an instance variable using the same syntax we used to write them:

int x = blank.x;

The expression blank.x means "go to the object named blank and get the value of the member named x." In this case we assign that value to a local variable named x. Notice that there is no conflict between the local variable named x and the instance variable named x. The purpose of dot notation is to identify which variable you are referring to unambiguously.

You can use dot notation as part of any expression, so the following are legal.

cout << blank.x << ", " << blank.y << endl; 
double distance = sqrt(blank.x * blank.x + blank.y * blank.y);

The first line outputs 3, 4; the second line calculates the value 5.

Operations on structures 

Most of the operators we have been using on other types, like mathematical operators ( +, %, etc.) and comparison operators (==, >, etc.), do not work on structures. Actually, it is possible to define the meaning of these operators for the new type, but we won't do that in this book.

On the other hand, the assignment operator does work for structures. It can be used in two ways: to initialize the instance variables of a structure or to copy the instance variables from one structure to another. An initialization looks like this:

Point blank = { 3.0, 4.0 };

The values in curly brackets get assigned to the instance variables of the structure one by one, in order. So in this case, x gets the first value and y gets the second.

Unfortunately, this syntax can be used only in an initialization, not in an assignment statement. Therefore, the following is illegal.

Point blank; 
blank = { 3.0, 4.0 }; // WRONG !!

You might wonder why this perfectly reasonable statement should be illegal, and there is no good answer. (Note, however, that a similar syntax is legal in C since 1999, and is under consideration for possible inclusion in C++ in the future.)

On the other hand, it is legal to assign one structure to another. For example:

Point p1 = { 3.0, 4.0 }; 
Point p2 = p1; 
cout << p2.x << ", " <<  p2.y << endl;

The output of this program is 3, 4.

Structures as return types 

You can write functions that return structures. For example, findCenter takes a Rectangle as an argument and returns a Point that contains the coordinates of the center of the Rectangle:

Point findCenter (Rectangle& box) 
{ 
  double x = box.corner.x + box.width/2; 
  double y = box.corner.y + box.height/2; 
  Point result = {x, y}; 
  return result; 
}

To call this function, we have to pass a box as an argument (notice that it is being passed by reference), and assign the return value to a Point variable:

Rectangle box = { {0.0, 0.0}, 100, 200 }; 
Point center = findCenter (box); 
printPoint (center);

The output of this program is (50, 100).

Passing other types by reference 

It's not just structures that can be passed by reference. All the other types we've seen can, too. For example, to swap two integers, we could write something like:

void swap (int& x, int& y) 
{ 
  int temp = x; 
  x = y; 
  y = temp; 
}

We would call this function in the usual way:

int i = 7; 
int j = 9; 
swap (i, j); 
cout << i << j << endl;

The output of this program is 97. Draw a stack diagram for this program to convince yourself this is true. If the parameters x and y were declared as regular parameters (without the &s), swap would not work. It would modify x and y and have no effect on i and j.

When people start passing things like integers by reference, they often try to use an expression as a reference argument. For example:

int i = 7; 
int j = 9; 
swap (i, j+1); // WRONG!!

This is not legal because the expression j+1 is not a variable — it does not occupy a location that the reference can refer to. It is a little tricky to figure out exactly what kinds of expressions can be passed by reference. For now, a good rule of thumb is that reference arguments have to be variables.

Pointers and structures

Structures can also be pointed by pointers and store pointers. The rules are the same as for any fundamental data type. The pointer must be declared as a pointer to the structure.

Nesting structures[edit]

Structures can also be nested so that a valid element of a structure can also be another structure.

//of course you have to define the Point struct first!
 
struct Rectangle {
 Point upper_left; 
 Point upper_right;
 Point lower_left;
 Point lower_right;
};

this[edit]

The this keyword is an implicitly created pointer that is only accessible within nonstatic member functions of a struct (or a union or class) and points to the object for which the member function is called. This pointer is not available in static member functions. This will be restated again on when introducing unions a more in depth analysis is provided in the Section about classes.