Starting from:

$25

CPEN333 -  Software Systems Engineering - Lab 1 - Solved

 This lab is simply a series of exercises to practice your object oriented C++ programming with Microsoft’s Visual C++ integrated development environment.

 

To carry out this and future labs in the course you will need access to the handout ‘Making Concurrent Visual C++ projects’ available on the course web-site. Please print this and bring it along to the lab (or access it on-line as required). We are going to start off by writing a single program i.e. a program with one function ‘main()’ composed from a number of  source ‘.cpp’ and header ‘.h’ files along with some classes and member functions. 

 

You should carry out this exercise while reading Lec0 - Introduction to C++

 

IMPORTANT: Some of the exercises below ask you to create code and then later that code is modified. When grading, the TAs will be looking for both versions, so either comment out the original code, prior to modification, or create other source files or use other creative means to preserve your original code for grading purposes.

 

Part A – 6 exercises worth 10% each

 

Exercise 1)      

 

Create a new project using Visual C++, call it what ever you want (see handout on using Microsoft visual C++). Create a source file called CBulb.cpp and a header file called CBulb.h and associate them with this project. Using the files appropriately follow these steps. 

 

Important: Don't forget to put this type of code at the start and end of your header file (this is something you have probably seen in a different course)

 

#ifndef   __CBulb__

#define   __CBulb__

 

// code for your CBulb class

 

#endif 

This code prevents inclusion of the same header file more than once when compiling a new source file. You should do something similar to this for all new header files you create during this lab.

 

a)      Create a class called CBulb that has a single private integer called state that enables the state of the bulb to represented (0 = off, 1 = on). Add a public print function that prints the numeric value of the private variable state. Add another public function called setstate that allows the variable state to be assigned a value.

b)      Inside a new main.cpp source file, write a function main() that creates an instance of the CBulb class i.e. a CBulb object and test the functions print and setstate. (Remember to #include the CBulb header file into your main.cpp source file). 

c)      Modify and test the program by adding a constructor function that initialises the state variable to zero. A constructor is a member function with the same name as the class name and which has no return type, not even void. (Note: All classes should have a constructor to initialise the state of the object being created.). Include code in the constructor to print out a simple message such as "CBulb Constructor being called.." when it is being called - this will help us understand when constructors are being called.

d)      The setstate function will still work OK and will allow the state to be set to 0 or 1 but the user of the bulb object could inadvertently set the state variable to an illegal value. Improve the class by adding two functions called on() and off() that set the state variable to 1 and 0 respectively. Test the new functions using your main() and when it is working COMMENT OUT the setstate function. (As class designers we should design classes that are intuitive to users and restrict misuse of the class)

e)      Modify the print function to print “on” and “off” depending on the value of the state variable. Modify the main() function to test your new print function.

f)       Add a function getstate that returns the value of the variable state. Modify the main() function to test getstate.

g)      Add another private integer variable called watts. (representing the power of the bulb) Modify the CBulb constructor to take an integer argument that is used to initialise the variable watts. Also add a default CBulb constructor that takes no arguments and set the wattage of the bulb to 0 and its state to off this constructor can print out a message such "CBulb Default Constructor being called.." this will help us understand when constructors are being called.

h)      Add two further functions: setwatts to set the wattage of the bulb to a specified value and getPower that returns the real-time power used by the bulb. This should be zero if the state of the bulb is off and the value of watts if the state of the bulb is on. Modify the main() function to test your new code - try turning the bulb on and off and printing the power it is using.

i)        Add a destructor for the CBulb class e.g. the function ~CBulb() and include code in the destructor to print out a simple message such as "CBulb destructor being called.." when it is being called - this will help us understand when destructors are being called.

 

Exercise 2)



2)      Create a new source file CSwitch.cpp and header file CSwitch.h and associate them with this project. Now create a new class CSwitch to represent a simple on/off type “toggle” switch. Add a private integer variable called state to represent the state of the switch and then add the following functions :-

 

A default CSwitch constructor that initialises the switch to the off state. Get the constructor to print out a message such as "CSwitch constructor being called" this will help us understand when destructors are being called. Also create

 

void turnon( )  – to turn the switch on

void turnoff( ) – to turn the switch off

void getState() – return the switch state

void print( ) – to print the state of the switch

 

Add a destructor for the CSwitch class e.g. the function ~CSwitch() and include code in the destructor to print out a simple message such as "CSwitch destructor being called.." this will help us understand when destructors are being called.

 

Write code in your existing main() function to create a new switch object and test the new member functions above. (Remember to #include the CSwitch header file)

 

Exercise 3)



3)      Create a new source file CLamp3Bulb.cpp and a header file CLamp3Bulb.h and add them to this project. Inside your CLamp class put, as private variables, one instance of a switch object and a fixed size array of 3 bulb objects. You will have to #include the header files CSwitch.h and CBulb.h into your CLamp3Bulb class – so the compiler knows what these class are.

Add a constructor and the following functions :-

CLamp3Bulb(int w1, int w2, int w3) – a constructor that will construct the lamp and set the wattage of the 3 bulb variables to the value of w1, w2 and w3 and their state to off, and a CSwitch object initialised to the off state. Get the constructor to print a message (as we did with the other classes) to show when it is being called.



      A destructor ~CLamp3Bulb() which prints out a message when it being called.

 

Also add these functions

    

void LampOn() – turn switch and all 3 bulbs on

void LampOff() – turn switch and 3 bulbs off

void print() – to print state of lamp i.e. on or off

 

int    getState() - return the state of the switch in the Lamp

int    getPower() – return power currently actually being consumed by the lamp (based on state).

 

 

Write code in your main() function to test your new CLamp3Bulb class and the functions above. Observe the various constructors and destructors being called - can you explain what is happening?

 

Exercise 4)

 

4)      Instead of embedding objects directly within another object (as member variables –where we put an instance of a bulb and switch inside a lamp) we can achieve the same effect using pointers.  Rewrite the CLamp3Lamp class developed earlier so that instead of using CSwitch and CBulb objects directly as member variables, we instead create pointers to a CSwitch and an array of pointers to 3 CBulb objects. Write the CLamp3Bulb constructor so that it takes integer wattage values for the 3 bulbs and constructs the bulbs and switch in the OFF state, with the specified bulb wattages. 

 

Notes to help:

 

We can create the pointers to objects as member variables inside our Lamp class like this

 

CBulb               *myBulbs[3] ;
CSwitch           *mySwitch ;

 

Then in the CLamp constructor we have to create and make them point to their actual bulb and switch objects and in the case of the bulb, specify its wattage.



mySwitch = new CSwitch(0) ;              // create new switch in off state

myBulbs[0] = new CBulb( theWatts ) ; // create new wattage bulb in off state

 

Now because the mySwitch variable is a pointers rather than an actual object, we must use the indirection operator ‘->’ rather than via the dot ‘.’ to access the real bulb and switch objects.

 

mySwitch  -> turnon() ;

mySwitch  -> turnoff() ;

 

myBulbs[0] -> on() ;

myBulbs[0] -> off() ;

 

One point that must also be considered is destroying the CBulb and CSwitch objects when they are no longer required, i.e. when the CLamp3bulb object is destroyed. You will recall that when an object is destroyed, it’s destructor will be called, so inside the CLamp3bulb destructor, we must use ‘delete’ and specify the pointer to the bulb and switch object we are trying to delete. For example to destroy a CBulb object and release the memory it occupies we would write this inside the destructor for the CLamp3bulb class. Note myBulb below is a pointer (not an object)

 

delete   myBulb[0];

 

This will cause the CBulb destructor to be called for the deleted bulb. Failure to do this may lead to “memory leaks” and an incorrectly ‘deconstructed’ object. Note that had we left the bulb and switch as actual variables rather than pointers to those variables, they would have been destroyed automatically and their memory recovered by the operating system.

 

Replacing fixed bulb and switch objects inside our Lamp class with pointers to those objects allows us to “swap” out a bulb and replace it with a new one (perhaps with a different wattage). 

 

To simulate this “real” concept, add a function to the CLamp class that allows one of the bulbs in the lamp to be exchanged with another one. That is you pass it a pointer to a new bulb, the Lamp takes ownership of that new bulb and returns back a pointer to the old bulb, i.e. we give back the old bulb to whoever is exchanging it. They can then take care of deleting it.

 

For example, the signature for the exchange function inside the lamp would look like this, where bulbNumber is in the range 0-2

 

CBulb *exchange(CBulb *newBulb,   int bulbNumber)

{

      // take ownership of the new bulb and return the pointer to the old bulb

}

 

 

 

 

 

 

In main(), we could now do this

 

main()

{

      CLamp3Bulb   L1(100,100,100) ;         // create a new Lamp with a 3x100 w bulbs

      …

      …

      CBulb *b1 = new CBulb(60) ;               // create a new 60w bulb and a pointer to it

 

      

      b1 = L1.exchange(b1, 0) ;            // give new bulb and save pointer to old bulb

                                                         // if lamp is on during exchange, turn on bulb

      delete b1 ;                                    // main destroys old bulb

}

 

Exercise 5)



This one is a little trickier. Add a copy constructor to the CLamp3Bulb class. This would allow us to write this in main()

 

main()

{

            CLamp3Bulb    L1 (100) ;

            …

            CLamp3Bulb     L2 (L1) ;           // invoke copy constructor to copy L1 into L2

}

 

The copy constructor would look something like this, although there is a little bit of code missing (see lecture 0 which is a refresher on C++ and covers copy constructor operation and coding)

 

CLamp3Bulb::CLamp3Bulb (const CLamp3Bulb      &LampToCopy)

{

            // create a switch and 3 new bulbs based on the state and values of

            // the LampToCopy object. Now copy their individual data to the new lamp

}

 

Notes on Copy Construction: The default method of passing arguments to functions (which includes passing objects to constructors like that above) is by value i.e. a simple copy of the argument/object is made. 

 

Normally this is not a problem as the compiler simply duplicates the values of all the member variables inside the object and passes those. If the object only had two integers then both integers are duplicated and their values copied to the duplicate object and there’s no problem. 

 

However if any of the member variables are pointers (such as myBulbs and mySwitch in the CLamp class above) then, when the CLamp3bulb copy constructor above is called, it would be the value of the pointers that would be copied/duplicated. This would mean that the new Lamp and the copied Lamp objects would both have pointers to the same bulbs and switch objects, the semantics of which mean that both lamps would then be sharing the same switch and bulbs which is conceptually wrong. In the case of a Lamp, it should have its own switch and bulbs, they can’t be shared with other lamps. 

 

It’s not enough then to simply copy the value of the pointers, we have to “clone” the 3 bulbs and switch objects they point to as well, i.e. make new bulb and switch objects for our new lamp with exactly the same values/states as the “donor” or source lamp. This is called a “deep copy”. 


This means that copy constructors must also exist for both the CBulb and CSwitch classes as well, but since those classes do not contain any pointers, only simple variables like state and wattage, the compiler will supply a default copy constructor to copy them (by value) which we can use without having to write them ourselves.

 

ToDo: Write the copy constructor for the CLamp3Bulb class to perform a “deep copy”.



Exercise 6) Using Inheritance

 

In this exercise we'll demonstrate a simple use of inheritance (refer back to Lec 0 - introduction to C++)

 

Create a new class called CPullLamp by creating a new CPullLamp.cpp and a CPullLamp.h header file and add them to the project. The new CPullLamp class is a "kind of" lamp in that it has all the properties of a lamp, e.g. on and off functionality, but it differs slightly because it has a pull cord that can toggle the state of the lamp each time we pull it (i.e. has modified or additional behaviour). 

 

Given that 90% of the behaviour of this new lamp already exists for us in the CLamp3Bulb class, we can put inheritance to good use and "borrow" pre-existing code to create our new class. Here is how we use inheritance to create the CPullLamp

 

class CPullLamp : public CLamp3Bulb

{

            // public and private variables and functions for the new lamp

}

 

Note that when we use inheritance, it's as if the compiler has automatically put a copy of the base class CLamp3Bulb object inside our new derived CPullLamp object for us (it's hidden so we don't have to declare it) however all those functions we wrote for the CLamp3Bulb can be also called for the CPullLamp, as if they were actual member functions of CPullLamp. 

 

Add the constructor below for the CPullLamp class that takes 3 integer variables w1, w2 and w3 and uses them to initialise the wattage of the 3 bulbs in the base class CLamp3Bulb.

 

CPullLamp::CPullLamp(int w1, int w2, int w3)

            : CLamp3Bulb(w1, w2, w3)                 // call base class constructor with watts

{

            printf("CPullLamp constructor called…\n");

}

 

Now that we have a new class, we can write the following code, which demonstrates how we can be apply the inherited functions such as getPower(), LampOn() and LampOff() to our new CPullLamp object.

 

main()

{

            CPullLamp       L1(100, 100, 100) ;      // create a Pull Lamp with 100 watt bulbs

 

            L1.LampOn() ;

            printf("Power of Lamp = %d\n", L1.getPower()) ;      // print power

 

            CBulb *b1 = new CBulb(50);                           // create new 50 watt bulb

            b1 = L1.exchange(b1 , 0) ;                               // swap bulb 0 for 50 watt bulb

 

            delete b1;                                                        // delete the old bulb

 

printf("Power of Lamp = %d\n", L1.getPower()) ;      // print power (250 watts)

            L1.LampOff() ;

 

printf("Power of Lamp = %d\n", L1.getPower()) ;      // print power

 

}

 

However, the CPullLamp class is not yet behaving like a toggle lamp since the only functions we have to manipulate the lamp are the ones we inherited from the CLamp3Bulb class i.e. LampOn() and LampOff(). 

 

Let's remedy this by add a toggle() function to the CPulledLamp class. This demonstrates an important concept in that we can 'add' new functions to our derived class, i.e. our new class contains the functions from the base class plus any new ones we add for our derived class.

 

void CPulledLamp::toggle()

{

            if(getState() == 0)        // if lamp is off

                        LampOn() ;      // turn on CPulledLamp using inherited functions

            else

                        LampOff() ;

}

 

Now we have a toggle function and can thus call this function in main() e.g.

 

main()

{

            CPullLamp       L1(100, 100, 100) ;      // create a Pull Lamp with 100 watt bulbs

 

            L1.toggle() ;

            printf("Power of Lamp = %d\n", L1.getPower()) ;      // print power

 

            L1.toggle() ;

printf("Power of Lamp = %d\n", L1.getPower()) ;      // print power

 

}

 

However our pulled lamp is not quite perfect as we can still call LampOn() and LampOff() which shouldn't be possible for a lamp with a pull cord and a toggle action (remember, when you inherit from a base class, you inherit everything, member functions and member variables – it’s not selective), so how do we fix this - we can't take out those functions since they are part of the base class CLamp3Bulb and someone who only wants a CLamp3Bulb object in their program will want those functions so we have to leave them there.

 

One way to solve this is to override those base class functions, i.e. redefine their behaviour in the new derived class. For example, we could redefine those functions with the private access specifier so that they cannot be called by users of the CPullLamp class e.g. inside the CPullLamp class we could write this

 

class CPullLamp : public CLamp3Bulb

{

            // public and private variables and functions for the new lamp

 

            private: 

                        void LampOn() { }                    // empty private function

                        void LampOff() { }                    // empty private function

}

 

Now if we say this in main(), we will get a compile time error

 

main()

{

            CPullLamp       L1(100, 100, 100) ;      // create a Pull Lamp with 100 watt bulbs

 

            L1.LampOn() ;                                     // error LampOn is private for CPullLamp

}

 

Note however that our toggle function will need to be re-written to make sure the old inherited (base-class) on() and off() functions are called (not the new empty private ones defined above which would take precedence for the CPullLamp class) e.g.

 

void CPulledLamp::toggle()

{

            if(getState() == 0)                                // if lamp is off, i.e. test state of base class

                    CLamp3Bulb::LampOn() ;             // call base class function LampOn()

            else

                    CLamp3Bulb::LampOff() ;

}

 

 

Part B) 

 

Exercise 1) Building a Linked List based on Classes (20%)

 

In a previous CPSC course you learned about dynamic data structures, an example of which was a linked list. Here you learned how to manipulate pointers and dynamically allocate memory so that new nodes could be added to a list and it would automatically grow in size. Using the functions you developed in that course, see if you can combine the various functions and data into a linked list class to hold integers, it might look something like this although the exact functionality is up to you. 

 

Note a Node could be a simple 'C' like structure which contains a pointer to the next node in a list plus a pointer to the data in that node. If you like you can turn the Node structure into a new class called Node

 

class List          {

            private :  Node *ptr ;               // pointer to 1st node in list

 

            public:  List();                          // default constructor sets ptr to null

                        ~List();                         // destructor to delete list and all nodes/data

                         Insert(….);                   // add a new node to the end of the list

                         Delete(…);                  // delete a node at the end of the list

                         Get(int i);                    // get some data from the list e.g. 5th item etc

};

 

Write a main() program to create some list objects and then call functions to insert, delete, get data etc from the list (and print that data)                           (20%)

 

 

Exercise 2) Building a linked list based on Template classes (20%)

 

Read about template classes here (http://www.cplusplus.com/doc/oldtutorial/templates/ )

 

Turn your dedicated linked list (one that only accepts integer data), into a template class that the compiler can turn into a list that accepts data of type ‘T’ (where T is any kind of data, e.g. int, float, double etc or better still, classes like CBulb, CLamp etc.

 

Note : For a template class, the Class declaration and its member functions HAVE to be written in the same header file (i.e. you cannot separate them out into header and source files). This a limitation of using template classes in C++

 

If you do this correctly, you should be able to write things like this

 

CList <int>       L1;                   // a list that holds integers

L1.insert (5);

 

And also something like this:-

 

CBulb                    b1(100) ;                              // create a 100 watt bulb

CSwitch                s1;

 

CList <CBulb *>                 L2;                          // A list that holds pointers to CBulb objects

CList <CSwitch *>             L3;                          // A list that holds pointers to CSwitch objects

 

L2.Insert(&b1) ;                                 // Correct: add a pointer to bulb ‘b1’ to the list

L3.Insert(&s1);                                  // Correct: add a pointer to switch ‘s1’ to the list

 

More importantly, the following code snippet should create some compiler errors

 

L2.Insert(5);                       // Error cannot add an int to a list that only accepts CBulb pointers

L3.Insert(5);                       // Error cannot add an int to a list that only accepts CSwitch pointers

L2.Insert(&s1);                  // Error cannot add a CSwitch pointer to this list of CBulb pointers

L3.Insert(&b1);                 // Error cannot add a CBulb pointer to this list of CSwitch pointers

 

 

Templates and template classes allow us to enforce type checking at compile time to make sure for example that we only get to insert the correct types of data into dynamic data structures. 

 

It also means (in this example) that the compiler can create, at compile time, different versions of the list data structures based on one copy of the source code, e.g. code for a list that holds int’s, code for one that holds bulb pointers etc. we don’t have to create lots of separate list source file (one for ints, one for bulb pointer etc), one can be written.                (20%)

 

Finally, for you to think/read about: The C++ standard template library (STL)

 

C++ has a library of dynamic data structures (called the standard template library or STL for short) which is standardised across compilers. A link to a set of HTML files (viewable in your browser) .

 

In addition, take a look here, more for awareness than to digest, but feel free to play if you like. 

 

https://www.cprogramming.com/tutorial/stl/stllist.html

 

Note that the STL also has a string class which we can use to manipulate strings without having to think of them as arrays of characters any more, as well as lists, vectors, stacks, queues etc. Check out this simple C++ string class tutorial. It’s much easier to use than the old C style “arrays of char” approach. 

 

https://www.tutorialspoint.com/cplusplus/cpp_strings.htm

 

Although not standardized, some folks have written classes to represent date and time try Google’ing them.


More products