Introduction
The structure feature is a carry over from "C". Since "C++" provides most of what "C" has it provides support for structures.A structure can be used to group variables. As an example of declaring structures and using them.
File: s1.cpp
#include <iostream> using namespace std ; struct Circle { double radius; double diameter; double area; }; int main() { Circle object1 ; object1.radius = 2.4 ; object1.diameter = 2 * object1.radius ; cout << "object1.radius: " << object1.radius << " object1.diameter: " << object1.diameter << endl ; return(0) ; }
Output:
[amittal@hills Structures]$ ./a.out
object1.radius: 2.4 object1.diameter: 4.8
A struct object is created with the variable "object1" and then using the dot notation the variables are set. A struct's data members are public.
A structure can have a constructor similar to a class.
File: s2.cpp
#include <iostream> using namespace std ; struct Circle { double radius; double diameter; double area; Circle() { cout << "Constructor" << endl ; } }; int main() { Circle object1 ; object1.radius = 2.4 ; object1.diameter = 2 * object1.radius ; cout << "object1.radius: " << object1.radius << " object1.diameter: " << object1.diameter << endl ; return(0) ; }The above example shows the constructor getting called and an output statement printing the structure object's parameters. We can use the Structure as a Class object . The only difference is that the a structure's data members are public by default and a class's data members are private by default.
File: s3.cpp
#include <iostream> using namespace std ; struct Circle { double radius; double diameter; double area; }; int main() { Circle object1 ; object1.radius = 2.4 ; object1.diameter = 2 * object1.radius ; Circle object2 ; object2.radius = 2.4 ; object2.diameter = 2 * object1.radius ; if( object1 == object2 ) cout << "Two objects are equal." << endl ; else cout << "Two objects are not equal." << endl ; return(0) ; } $ g++ s3.cpp s3.cpp: In function ‘int main()’: s3.cpp:19:21: error: no match for ‘operator==’ (operand types are ‘Circle’ and ‘Circle’) 19 | if( object1 == object2 )If we try to compile the above we get a compiler error. We cannot compare 2 objects of Circle. We can compare the data members.
File: s4.cpp
#include <iostream> using namespace std ; struct Circle { double radius; double diameter; double area; }; int main() { Circle object1 = {2, 4, 25.12 }; cout << "object1.radius: " << object1.radius << " object1.diameter: " << object1.diameter << endl ; return(0) ; } Output: [amittal@hills Structures]$ ./a.out object1.radius: 2 object1.diameter: 4The above example shows how we can initialize a Circle object with some numerical values.
It is possible to declare a structure without a name. We can specify the object variable right after the structure definition.
File: s5.cpp
#include <iostream> using namespace std ; //A single variable //Can't create more variables struct { double radius; double diameter; double area; } object1 ; int main() { // Circle object1 ; object1.radius = 2.4 ; object1.diameter = 2 * object1.radius ; cout << "object1.radius: " << object1.radius << " object1.diameter: " << object1.diameter << endl ; return(0) ; }Note that it is also possible to define classes this way. Such classes are called anonymous classes.
File: c1.cpp
#include <iostream> using namespace std ; //A single variable //Can't create more variables class { public: double radius; double diameter; double area; } object1 ; int main() { // Circle object1 ; object1.radius = 2.4 ; object1.diameter = 2 * object1.radius ; cout << "object1.radius: " << object1.radius << " object1.diameter: " << object1.diameter << endl ; return(0) ;}Partial Initialization
We do not have to initialize a structure object with all the values.
File: s6.cpp
#include <iostream> using namespace std ; struct Circle { double radius; double diameter; double area; }; int main() { Circle object1 = {2 }; cout << "object1.radius: " << object1.radius << " object1.diameter: " << object1.diameter << endl ; return(0) ; } Output: [amittal@hills Structures]$ ./a.out object1.radius: 2 object1.diameter: 0In the above case the other data variables take on their default values which in this case is 0.
Arrays of Structures
File: s7.cpp
#include <iostream> using namespace std ; /* Arrays of objects*/ struct Circle { double radius; double diameter; double area; }; int main() { Circle circleArray[2] ; circleArray[0].radius = 2 ; circleArray[0].diameter = 4 ; circleArray[1].radius = 3 ; circleArray[1].diameter = 6 ; cout << "circleArray[0].radius: " << circleArray[0].radius << " circleArray[0].diameter: " << circleArray[0].diameter << endl ; cout << "circleArray[1].radius: " << circleArray[1].radius << " circleArray[1].diameter: " << circleArray[1].diameter << endl ; return(0) ; } Output: [amittal@hills Structures]$ ./a.out circleArray[0].radius: 2 circleArray[0].diameter: 4Initialization of arrays of structures.
File: s8.cpp
#include <iostream> using namespace std ; /* Arrays of objects*/ struct Circle { double radius; double diameter; double area; }; int main() { //Initialization of array structures Circle circleArray1[2] = { { 2 , 4, 25.12 } , { 1, 2 , 3.14 } } ; return(0) ; }
Nested Structures
We can have nested structures also as shown in this example.File: s9.cpp
#include <iostream> using namespace std ; /*Nested Structure*/ struct Circle { double radius; double diameter; double area; }; struct Shape { Circle circleObject ; int x1 ; }; int main() { Shape shape1 ; shape1.circleObject.radius = 1 ; shape1.circleObject.diameter = 2 ; shape1.circleObject.area = 3.14 ; return(0) ; }
Structures as arguments
File: s10.cpp
#include <iostream> using namespace std ; /*Passing Structure objects as arguments*/ struct Circle { double radius ; double diameter ; double area ; }; Circle fillCircle( Circle object1 ) { Circle object2 ; object2.radius = object1.radius ; object2.diameter = object1.diameter ; object2.area = object1.area ; return object2 ; } Circle& fillCircle1( Circle object1 ) { Circle object2 ; object2.radius = object1.radius ; object2.diameter = object1.diameter ; object2.area = object1.area ; return object2 ; } int main() { Circle object1 ; Circle object2 = fillCircle1( object1 ) ; Circle object3 = fillCircle( object1 ) ; return(0) ; }
The above example shows how structure objects can be passed to a function and returned from a function. The "fillCircle1" function has a mistake. It is returning a reference to a local object that gets destroyed when the function "fillCircle1" ends. We should either not return a reference and in that case a temporary object of type Circle will be returned or a reference to a global object that does not get destroyed. Compiling the above code produces a warning:
$ g++ s10.cpp s10.cpp: In function ‘Circle& fillCircle1(Circle)’: s10.cpp:26:16: warning: reference to local variable ‘object2’ returned [-Wreturn-local-addr] 26 | return object2 ;
Pointers to structures
File: s11.cpp
#include <iostream> using namespace std ; struct Circle { double radius ; double diameter ; double area ; }; int main() { Circle object1 ; Circle* ptrObject1 ; Circle* ptrObject2 ; object1.radius = 2 ; ptrObject1 = &object1 ; ptrObject2 = new Circle() ; cout << ptrObject1->radius << " : " << ptrObject2->radius << endl ; return(0) ; } Output: [amittal@hills Structures]$ g++ s11.cpp [amittal@hills Structures]$ ./a.exe 2 : 0We can have pointers to structures. The notation for accessing the data members for a pointer is the symbol "->" or useing "*" .
File: s12.cpp
#include <iostream> using namespace std ; /*Passing Structure objects as arguments*/ struct Circle { double radius ; double diameter ; double area ; }; int main() { Circle object1 ; Circle* ptrObject1 ; Circle* ptrObject2 ; object1.radius = 2 ; ptrObject1 = &object1 ; ptrObject2 = new Circle() ; cout << ptrObject1->radius << " : " << ptrObject2->radius << endl ; ptrObject2->radius = 10 ; cout << (*ptrObject2).radius << endl ; return(0) ; } Output: [amittal@hills Structures]$ ./a.exe 2 : 0 10The above example shows the syntax:
cout << (*ptrObject2).radius << endl ;
This is another way of accessing the data member for a pointer. The notation (*ptrObject2) will give us the object Circle and we can access the data member in the regular way of using the dot symbol "." .
Unions
A union is like a structure except that all the data members occupy the same location in RAM.File: s13.cpp
#include <iostream> using namespace std ; //----------------------------------- union test { char ch ; int x1 ; }; //----------------------------------- int main() { test unionObject ; unionObject.x1 = 32771 ; cout << unionObject.x1 << " : " << (int) unionObject.ch << endl ; return(0) ; } //----------------------------------- $ g++ s13.cpp ; ./a.exe 32771 : 3
The union "test" contains 2 data member variables "ch" and "x1". In RAM the union will look like: RAM --------- ch x1 unionObject Byte1 Byte2 Byte3 Byte4The amount of memory located is for the largest data variable in the union. Our union "test" has 2 data variables: "x1" and "ch" . An int occupies 4 bytes and a character occupies 1 byte so the memory allocated is 4 bytes. Now what sets Union apart is that both "ch" and "x1" share the same memory ! Both start from Byte1. Of course the character ch will only occupy "Byte1" and the int "x1" will occupy all the4 bytes. Let's assume our CPU is Intel which it is on the machine where this code was compiled and thus the integer is stored from lowest byte to highest byte.
We are storing the number 32771. Let's see what this number looks like in 4 bytes.
In hexadecimal: 00 00 80 03 When the bytes are arranged in RAM they show up as: 03 80 00 00 We can see that the byte value of 3 is stored in Byte1 . cout << unionObject.x1 << " : " << (int) unionObject.ch << endl ; We can see from the output that the value of "unionObject.ch" equals 3 .
Exercises
1) How much space is allocated for the below union.Confirm that by using the "sizeof" function.
File: ex1.cpp
#include <stdio.h> union empAdd { char *ename; char stname[20]; int pincode; }; int main() { return 0 ; }2)
File: ex2.cpp
#include <iostream> #include <string> #include <iomanip> using namespace std; struct Employee { int empNumber; // Employee number double hours; // Hours worked double payRate; // Hourly payRate }; int main() { Employee emp1 = { 1, 10 , 5 } ; // Create a second employee object and initialize it with emp2 with id 2 // hours 20 and payrate 6 //Print pay of emp1 and pay of emp2. Pay is hours * payRate }