C++ Intro

Lecture 8: struct


C++ structure: aggregation of data fields


In C++, an array is an aggregate of elements of the same type. A C++ struct is an aggregate of elements of arbitrary types. For example:


struct address {
    string  person_name;
    int     street_number;
    string  street_address;
    string  town;
    char    state[2];
    int     zipcode;
};

This defines a new type called address consisting of the items you need in order to send mail to someone. Note the semicolon at the end. This is one of very few places in C++ where it is necessary to have a semicolon after a curly brace, so people are prone to forget it.


C++ objects and access to their data members


Variables of type address are often referred to as C++ objects. They can be declared exactly as other variables, and the individual members can be accessed using the "." (dot) operator. For example:


#include <iostream>
#include <string>

struct address{ /*...*/ };

int main(int argc, char* argv[])
{
    address bcc;
    bcc.person_name = "Joe Doe";
    bcc.street_number = 777;
    bcc.street_address = "ELSBREE STREET";
    bcc.town = "FALL RIVER";
    bcc.state[ 0 ] = 'M';
    bcc.state[ 1 ] = 'A';
    bcc.zipcode = 2720;

    return 0;
}


Pointers to objects


Structure objects are often accessed through pointers using the "->" operator, also known as pointer-to-object dereference operator. For example:


#include <iostream>
#include <string>

struct address{ /*...*/ };  // address becomes new C++ type

int main(int argc, char* argv[])
{
    address adr;            // instantiate address object
    address* padr = &adr;   // create pointer to object
    paddr->person_name = "Frederick Charles Krueger";

    return 0;
}


Object as function argument


Objects of structure types can be passed as function arguments (either by value, or by object reference):


#include <iostream>
#include <string>

struct address{ /*...*/ };  // address becomes new C++ type

int main(int argc, char* argv[])
{
    address fictional_character;
    populate_address( fictional_character );

    return 0;
}

void populate_address( address& addr_ )
{
    addr_.person_name = "Frederick Charles Krueger";
    addr_.street_name = "Elm Street";
    addr_.town = "Springwood";
}


Object initialization


The address structure that we've used so far did not require a programmer to provide any kind of initialization. We were able to instantiate an object, and then use individual member variables to store the data. It is possible to establish a more formal protocol, which will require a set of initial values that will be used when the object is created. Consider


struct date{
    int month;
    int day;
    int year;
};

The structure named date could benefit from an explicit initialization of its member variables. For example, it would be nice to create a date object along with a set of values for its month, day, and year:


int main(int argc, char* argv[])
{
    date birthday( 12, 5, 1997 ); // instantiate and initialize the object

    return 0;
}


In order to allow this type of initialization, we must declare a special function inside our structure, which is called a constructor. The entire program will look like this:


struct date{
    int month;
    int day;
    int year;

    // Constructor:
    date( int month_, int day_, int year_ )
    {
        month = month_;
        day = day_;
        year = year_;
    }
};//struct date

int main(int argc, char* argv[])
{
    date birthday( 12, 5, 1997 ); // instantiate and initialize the object

    return 0;
}



Default constructor


Adding a constructor function to an object means that all objects of the user-defined type will be initialized, because each declaration will require a set of parameters to initialize the data members. In order to permit the old way of object creation, the default constructor must be provided; that is, a cnstructor that has no arguments. The default constructor typically initializes individual data members by setting them to the appropriate default values:


struct date{
    int month;
    int day;
    int year;

    // Default constructor:
    date()
    {
        month = 0;
        day = 0;
        year = 0;
    }

    // Constructor:
    date( int month_, int day_, int year_ )
    {
        month = month_;
        day = day_;
        year = year_;
    }
};//struct date

int main(int argc, char* argv[])
{
    date today;                   // default constructor is invoked
    date birthday( 12, 5, 1997 ); // instantiate and initialize the object

    return 0;
}



struct provides a way to establish a new user-defined C++ type


The definition of a structure provides a new user-defined C++ type to the program. A structure can have many different constructors to provide convenient ways to init the objects. Once created, an object, like other fundamental C++ types, can be used in many different ways. For example, the following program illustrates a vector of user-defined type date:


#include <iostream>
#include <vector>

struct date{
    int month;
    int day;
    int year;

    // Default constructor:
    date()
    {
        month = 0;
        day = 0;
        year = 0;
    }

    // Constructor:
    date( int month_, int day_, int year_ )
    {
        month = month_;
        day = day_;
        year = year_;
    }
};//struct date

int main(int argc, char* argv[])
{
    std::vector< date > week( 7 );
    week[ 0 ] = date( 4, 8, 2007 );
    week[ 1 ] = date( 4, 9, 2007 );
    week[ 2 ] = date( 4, 10, 2007 );
    week[ 3 ] = date( 4, 11, 2007 );
    week[ 4 ] = date( 4, 12, 2007 );
    week[ 5 ] = date( 4, 13, 2007 );
    week[ 6 ] = date( 4, 14, 2007 );
    return 0;
}