C++ Programming/Structures

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


[edit | edit source]

A structure is a compound data type that contains different members of different types. The members are accessed by their names. A value of a structure-object is a tuple of values of each member of the object. A structure can also be seen as a simple implementation of the object paradigm from (OOP). 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 */ {
 // declare public members here
 // declare protected members here
 // declare private members here

The optional keywords public:, protected:, private: declare the protection status of the following members. They can be put in any order, and more than one of each may occur. If no protection status is given, then the members are public. (Private or protected members can be accessed only by methods or friends of the structure; explained in a later chapter).

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.

Objects of type myStructType are declared using:

 /* struct */ myStructType obj1 /* , obj2, ... */;

Repeating the keyword struct at the beginning is optional.

It is possible to define objects directly in the struct definition instead of using a name for the struct-type:

 struct { /*members*/ } obj1 /*, obj2, .. */ ;

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:

double 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 function arguments and return types

You can write functions that take or 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:

struct Rectangle {
  Point corner;
  double width, height;

Point findCenter (const 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 Rectangle as an argument, and assign the return value to a Point variable:

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

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

Notice that the Rectangle is being passed to function findCenter by a reference (explained in chapter Functions), because this is more efficient than copying the whole structure what would be done on passing by value. The reference is declared constant, meaning that function findCenter will not modify the argument box, especially that mybox of the caller will remain unchanged.

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 | edit source]

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;

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.