Reading




--------------------------------------------------------------------------------------------------------------------
class with a parameterized  constructor
--------------------------------------------------------------------------------------------------------------------



for example

File: main1.cpp 

#include "cmpslib19.h"




class vehicle
{
	private:
		double displacement;
		int doors;
		bool automatic_transmission;
		string make;
		string model;


	public:
		// the constructor has NO return type at all , the name is ALWAYS the same as the class name
		// your constructor can have any number of parameters
		// you can have multiple constructors

		vehicle()
		{
			displacement =0;
			doors =0;
			automatic_transmission=false;
		}


		vehicle(double in_displacement,int in_doors, bool in_automatic_transmission)
		{
			displacement = in_displacement;
			doors = in_doors;
			automatic_transmission =in_automatic_transmission;

		}

		vehicle(double in_displacement,int in_doors, bool in_automatic_transmission, string in_make , string in_model)
		{
			displacement = in_displacement;
			doors = in_doors;
			automatic_transmission =in_automatic_transmission;
			make = in_make;
			model = in_model;
		}


}; // end of class

int main()
{

	vehicle vh1;  // uses the default constructor

	vehicle vh2(2000,2,true);  // use the constructor that has 3 parameters

	vehicle vh3(2000,2,false,"Toyota","Celica");  // use the constructor that has 5 parameters



}



given the above There is a complete and functional defenition for the class vehicle as well as a main that creates an instance of that class. Any time an instance of the class vehicle is created the code of one of the three constructors will be ran. -------------------------------------------------------------------------------------------------------------------- copy constructors -------------------------------------------------------------------------------------------------------------------- If your class uses pointers you will likely need a copy constructor this is so that you can pass them by value to functions... pass by value passes a copy... It cant pass a copy if it does not know how to copy.. it will try but if you have pointers it may be wrong here is some code that simply passes an instance of our class to a function pass by value but it doesnt have a copy constructor and the class uses a pointer to store and int that is dynamically allocated with new File: main5.cpp

#include"cmpslib19.h"


/* constructors and destructors are very handy when we want to 
   have them dynamically allocated
   Initializing them Cleaning up can be completely encapsulated into a class 

   lets try this in C

*/



class SimpleIntContainer
{
	public:
		int * data;
		SimpleIntContainer()
		{
			// we use new in the construcor so its a safe bet your need a copy constructor
			data = new int;
		}

		~SimpleIntContainer()
		{
			cout << "in destructor deleting the pointer for address: " << data << "\n\n";
			delete data;
		}

		void SetVal(int val)
		{
			*data = val;
		}

		void PrintVal()
		{
			cout << "data   address " << data << " value: " << *data << "\n\n";
		}

}; 



void PrintDetails(SimpleIntContainer input)
{
	cout << "the SimpleIntContainer passed to this function should be a COPY but data is a pointer.\n";
	cout << "note the address of data.. same as in main \n";
	cout << "data   address " << input.data << " value: " << *(input.data) << endl;
	input.SetVal( 100);
	// this should not change anything in the main as input should be a COPY of the value passed in
	// but the pointer address of data is the same ... 
	// at the end of this function the destructor of "input" will be called deleting memory assigned to the pointer "input.data"   
}





int main()
{

	SimpleIntContainer a;
	a.SetVal(5);
	a.PrintVal();

	PrintDetails(a); // TRY TO PASS A COPY OF a 

	// a.PrintVal()  should still print 5 but it wont
	a.PrintVal(); 


	// at the end of this function the destructor of "a" will be called deleting memory assigned to the pointer "a.data"   
	// since the addresses of input.data and a.data are the same... its already deleted 
	return 0;
}

/*
   output when run

msarr@odin> ./runme5 
data   address 0x55b53f6daeb0 value: 5

the SimpleIntContainer passed to this function should be a COPY but data is a pointer.
note the address of data.. same as in main 
data   address 0x55b53f6daeb0 value: 5
in destructor deleting the pointer for address: 0x55b53f6daeb0

data   address 0x55b53f6daeb0 value: 0

in destructor deleting the pointer for address: 0x55b53f6daeb0

free(): double free detected in tcache 2
Aborted


   you cant call delete on the same address more than once... boom!!!

*/




here is the same code but we added a proper copy constructor File: main6.cpp

#include"cmpslib19.h"


/* constructors and destructors are very handy when we want to 
   have them dynamically allocated
   Initializing them Cleaning up can be completely encapsulated into a class 

   lets try this in C

*/



class SimpleIntContainer
{
	public:
		int * data;
		SimpleIntContainer()
		{
			// we use new in the construcor so its a safe bet your need a copy constructor
			data = new int;
		}

        SimpleIntContainer(const SimpleIntContainer & rhs)
		{
        // our copy constructor
		data = new int; // allocate a new piece of memory for data to point to 
		*data = *(rhs.data); // copy the VALUE into the new memory

		}




		~SimpleIntContainer()
		{
            cout << "in destructor deleting the pointer for address: " << data << "\n\n";
			delete data;
		}

		void SetVal(int val)
		{
			*data = val;
		}

		void PrintVal()
		{
			cout << "data   address " << data << " value: " << *data << "\n\n";

		}

}; 



void PrintDetails(SimpleIntContainer input)
{
    cout << "the SimpleIntContainer passed to this function should be a COPY but data is a pointer.\n";
    cout << "note the address of data.. same as in main \n";
	cout << "data   address " << input.data << " value: " << *(input.data) << endl;
	input.SetVal( 100);
	// this should not change anything in the main as input should be a COPY of the value passed in
    // now that we have a proper copy construcor it works
    // this is inded a copy .. note the address of data different 
}





int main()
{

	SimpleIntContainer a;
	a.SetVal(5);
	a.PrintVal();

	PrintDetails(a); // TRY TO PASS A COPY OF a , it will work this time 
    // a.PrintVal()  should still print 5
    a.PrintVal(); 
   

    // at the end of this function the destructor of "a" will be called deleting memory assigned to the pointer "a.data"   
	return 0;
}

/*
output when run

msarr@odin> ./runme6 
data   address 0x55b7e31deeb0 value: 5

the SimpleIntContainer passed to this function should be a COPY but data is a pointer.
note the address of data.. same as in main 
data   address 0x55b7e31df2e0 value: 5
in destructor deleting the pointer for address: 0x55b7e31df2e0

data   address 0x55b7e31deeb0 value: 5

in destructor deleting the pointer for address: 0x55b7e31deeb0




it works now


*/




why is this ?? if you dont have a copy constructor, it will use a very simple one by default if your class has int count; int age; string * name; it will copy the value copy.count = count; // ok copy.age = age; // ok copy.name = name; // BAD and so forth if your data memeber is a pointer it copys the value so the original pointer and the copy pointer have THE SAME ADDRESS and often this is NOT what you want. the name of the original and the copy point to the EXACT same string not a copy so you either make a copy constructor or dont pass your class by value to a function. -------------------------------------------------------------------------------------------------------------------- destructors -------------------------------------------------------------------------------------------------------------------- a destructor is the opposite of a constructor, it runs when an instance is destroyed. File: main2.cpp

#include "cmpslib19.h"

class student_list
{
	private:
		string * data;
		int size;

	public:
		student_list( int in_size = 10)
		{
			size = in_size;
			data = new string[in_size];
		}

};


int main()
{
	student_list mylist; // mylist.data is set to a dynamic array of size 10
	student_list mylist2(38);//  mylist2.data is set to a dynamic array of size 38

}



in this senario the arrays do not get cleaned up. We dynamically allocate memory in the constructor with the new command. but we dont have anything to clean it up. we need some code that runs automatically when the objects are destroyed File: main3.cpp

#include "cmpslib19.h"


class student_list
{
	private:
		string * data;
		int size;
	public:
		student_list( int in_size = 10)
		{
			size = in_size;
			data = new string[in_size];
		}


		// here is a destructor  it has no parameters and no return type
		// it is always named the same as the class with a ~ preceeding it
		// here we would clean up anything we created with new in the constructor
		~student_list()
		{
			delete[] data;
		}

};


int main()
{
	student_list mylist; // mylist.data is set to a dynamic array of size 10
	student_list mylist2(38);// mylist2.data is set to a dynamic array of size 38

}