Inheritance and Polymorphism

I have to create a grocery store checkout that shows the reciept. I have all of the following code and it starts to load but in the process runs into an error and I cannot figure out what I am doing wrong.

defs.h
1
2
3
4
5
6
7
#ifndef DEFS_H
#define DEFS_H

const int NAME_WIDTH = 15;   // Width of name field on grocery recipt
const int COST_WIDTH = 6;    // width of cost field on grocery recipt

#endif 


Item.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#ifndef ITEM_H
#define ITEM_H

#include <ostream>
#include <iomanip>
using namespace std;

#include "defs.h"    // Specifies field widths for grocery receipt

class Item 
{
public:
    Item(const char* name = "");          // constructor
    virtual ~Item();                      // destructor
    Item(const Item& other);              // copy constructor
    Item& operator=(const Item& rhs);     // assignment operator

    const char* name() const;             // return the name of item

    virtual int cost() const = 0;         // return cost of item in cents
    virtual void print(ostream& out) const = 0; // print the item to out

private:
    char* myName;   // dynamically allocated character array
};

#endif 


Item.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>  
#include "Item.h"  
using namespace std;  

//default constructor for Item class 
Item::Item( const char* name )  
{  
	int nameSize = strlen(name);  
	char *myName = new char[nameSize + 1];// dynamically allocate space for char array myName based on size of name  
}//end default constructor  

//class Item destructor  
Item::~Item()  
{  
	delete [] myName;//release pointer-based array space  
}//end destructor  

//copy constructor for Item class  
Item::Item( const Item &other )  
{ 
	int nameSize = strlen( other.myName );  
	char *myName = new char[nameSize + 1];// dynamically allocate space for char array myName based on size of name  
	
	for( int i = 0; i < nameSize; i++ )//iterate through both arrays  
		myName[ i ] = other.myName[ i ];//copy name's characters into myName array  
}//end copy constructor  

//overloaded assignment operator 
Item &Item::operator =(const Item &rhs)  
{  
	if( &rhs != this )//don't self-assign  
	{  
		int myNameSize = strlen( rhs.myName );//get size of rhs  
		
		//if arrays are different sizes, deallocate original  
		//and reallocate based on size of rhs  
		if( strlen( myName ) != strlen( rhs.myName ) )  
		{  
			delete [] myName;//deallocate space    
			myName = new char[ myNameSize ];//reallocate space based on new size  
		}//end if  
		
		for( int i = 0; i < myNameSize; i++ )   
			myName[ i ] = rhs.myName[ i ];//copy array into object  
	}//end if  
	return *this;//enables multiple assignment  
}//end overloaded operator=  

void Item::print(ostream& out ) const 
{  
	cout << cost() << myName << endl;
}


CannedGood.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include<iostream>

#include "item.h"
using namespace std;

class CannedGood : public Item
{

public:
    CannedGood( const char* name, const int & ); //default constructor
    virtual ~CannedGood();                  //virtual destructor
    CannedGood( const CannedGood& other );  //copy constructor
    CannedGood& operator=( const CannedGood& rhs ); //overloaded assignment operator

    const char* getName() const;             // return the name of item

    int cost() const;               //return cost of the item in cents
    virtual void print( ostream& out ) const; //print the item

private: 
    char* myName;  //dynamically allocated character array
    int cannedCost; //integer value of the cost of the canned good
};
#endif  


CannedGood.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include<iostream>  
#include "CannedGood.h" //CannedGood class definition  
using namespace std;  

//default constructor for CannedGood class  
CannedGood::CannedGood( const char* name, const int &cGCost )  
	:Item( name )  
{  
	int nameSize = strlen(name);  
	char *myName = new char[nameSize + 1];// dynamically allocate space for char array myName based on size of name  
	cannedCost = cGCost; //store passed cost value in private cost variable  
}//end default constructor  

//class CannedGood destructor  
CannedGood::~CannedGood()  
{  
	delete [] myName;//release pointer-based array space  
}//end destructor  

//copy constructor for CannedGood class  
CannedGood::CannedGood(const CannedGood &other) 
{  
	cannedCost = other.cost(); //assign cost of other variable to this cost  
	int nameSize = strlen( other.myName );  
	myName = new char[ nameSize ];//dynamically allocate space for char array myName based on size of name  
	
	for( int i = 0; i < nameSize; i++ )//iterate through both arrays  
	{  
		myName[ i ] = other.myName[ i ];//copy name's characters into myName array  
	}  
}//end copy constructor 

//overloaded assignment operator  
CannedGood &CannedGood::operator =(const CannedGood &rhs)  
{  
	if( &rhs != this )//don't self-assign  
	{  
		int myNameSize = strlen( rhs.myName );//get size of rhs  
		
		//if arrays are different sizes, deallocate original  
		//and reallocate based on size of rhs 
		if( strlen( myName ) != strlen( rhs.myName ) )  
		{  
			delete [] myName;//deallocate space 
			myName = new char[ myNameSize ];//reallocate space based on new size  
		}//end if  
		
		for( int i = 0; i < myNameSize; i++ )   
			myName[ i ] = rhs.myName[ i ];//copy array into object  
		cannedCost = rhs.cost();  
	}//end if  
	
	return *this;//enables multiple assignment  
}//end overloaded operator=  

//function to return name of the Item  
const char* CannedGood::getName() const 
{  
	return myName;//return private variable myName  
}//end function name()  

//cost function to return cost of canned good in cents  
int CannedGood::cost() const
{  
	return cannedCost;//return the private variable cost  
}//end member-function cost  

//member-function to print the CannedGood  
void CannedGood::print( ostream &out ) const 
{  
	cout << setw( NAME_WIDTH ) << getName() << "" 
		<< setfill(' ') << setw( COST_WIDTH ) << cost()/100; //output canned good's name followed by its cost  
}//end member-function print  


It was too long so here is more

Coupon.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#ifndef COUPON_H
#define COUPON_H

#include<iostream>

#include "item.h"
using namespace std;

class Coupon : public Item
{

public:
    Coupon( const char* name, const int & ); //default constructor
    virtual ~Coupon();                  //virtual destructor
    Coupon( const Coupon& other );  //copy constructor
    Coupon& operator=( const Coupon& rhs ); //overloaded assignment operator

    const char* getName() const;             // return the name of item

    int cost() const;               //return cost of the item in cents
    virtual void print( ostream& out ) const; //print the item

private: 
    char* myName;  //dynamically allocated character array
    int couponCost; //integer value of the cost of the canned good
};
#endif  


Coupon.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include<iostream>
#include "Coupon.h" //Coupon class definition
using namespace std;

//default constructor for Coupon class
Coupon::Coupon( const char* name, const int &cGCost )
:Item( name )
{
    int nameSize = strlen(name);
    char *myName = new char[nameSize + 1];// dynamically allocate space for char array myName based on size of name

    
    couponCost = ( cGCost > 0 ? cGCost: 0 ); //store passed cost value in private cost variable
}//end default constructor

//class Coupon destructor
Coupon::~Coupon()
{
    delete [] myName;//release pointer-based array space
}//end destructor

//copy constructor for Coupon class
Coupon::Coupon(const Coupon &other)
{
    couponCost = other.cost(); //assign cost of other variable to this cost
    int nameSize = strlen( other.myName );
    myName = new char[ nameSize ];//dynamically allocate space for char array myName based on size of name

    for( int i = 0; i < nameSize; i++ )//iterate through both arrays
    {
        myName[ i ] = other.myName[ i ];//copy name's characters into myName array
    }
}//end copy constructor

//overloaded assignment operator
Coupon &Coupon::operator =(const Coupon &rhs)
{
    if( &rhs != this )//don't self-assign
    {
        int myNameSize = strlen( rhs.myName );//get size of rhs
        //if arrays are different sizes, deallocate original
        //and reallocate based on size of rhs
        if( strlen( myName ) != strlen( rhs.myName ) )
        {
            delete [] myName;//deallocate space            
            myName = new char[ myNameSize ];//reallocate space based on new size
        }//end if

        for( int i = 0; i < myNameSize; i++ ) 
            myName[ i ] = rhs.myName[ i ];//copy array into object
        couponCost = rhs.cost();
    }//end if

    return *this;//enables multiple assignment
}//end overloaded operator=

//function to return name of the Item
const char* Coupon::getName() const
{
    return myName;//return private variable myName
}//end function name()

//cost function to return cost of coupon in cents
int Coupon::cost() const
{
    return couponCost;//return the private variable cost
}//end member-function cost

//member-function to print the Coupon
void Coupon::print( ostream &out ) const
{
    cout << setw( NAME_WIDTH ) << getName() << ""
         << setfill(' ') << setw( COST_WIDTH ) << cost()/100; //output coupon's name followed by its cost

}//end member-function print  


Produce.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#ifndef PRODUCE_H
#define PRODUCE_H

#include<iostream>

#include "item.h"
using namespace std;

class Produce : public Item
{

public:
    Produce( const char* name, const double &, const int & ); //default constructor
    virtual ~Produce();                  //virtual destructor
    Produce( const Produce& other );  //copy constructor
    Produce& operator=( const Produce& rhs ); //overloaded assignment operator

    double getWeight() const;                  //return weight of the produce
    const char* getName() const;             // return the name of item

    int cost() const;               //return cost of the item in cents
    virtual void print( ostream& out ) const; //print the item

private: 
    char* myName;  //dynamically allocated character array
    int produceCost; //integer value of the cost of the canned good
    double weight; //double value of weight of produce in pounds
};
#endif  


Produce.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include<iostream>
#include "Produce.h" //Produce class definition
using namespace std;

//default constructor for Produce class
Produce::Produce( const char* name, const double &pWeight, const int &cGCost )
:Item( name )
{
    int nameSize = strlen(name);
    myName = new char[ nameSize ];//dynamically allocate space for char array myName based on size of name
    
    produceCost = cGCost; //store passed cost value in private cost variable
    weight = pWeight; //store passed weight value in private weight variable
}//end default constructor

//class Produce destructor
Produce::~Produce()
{
    delete [] myName;//release pointer-based array space
}//end destructor

//copy constructor for Produce class
Produce::Produce(const Produce &other)
{
    produceCost = other.cost(); //assign cost of other variable to this cost
    weight = other.getWeight(); //assign weight of other variable to this weight
    int nameSize = strlen( other.myName );
    char *myName = new char[nameSize + 1];// dynamically allocate space for char array myName based on size of name


    for( int i = 0; i < nameSize; i++ )//iterate through both arrays
    {
        myName[ i ] = other.myName[ i ];//copy name's characters into myName array
    }
}//end copy constructor

//overloaded assignment operator
Produce &Produce::operator =(const Produce &rhs)
{
    if( &rhs != this )//don't self-assign
    {
        int myNameSize = strlen( rhs.myName );//get size of rhs
        //if arrays are different sizes, deallocate original
        //and reallocate based on size of rhs
        if( strlen( myName ) != strlen( rhs.myName ) )
        {
            delete [] myName;//deallocate space            
            myName = new char[ myNameSize ];//reallocate space based on new size
        }//end if

        for( int i = 0; i < myNameSize; i++ ) 
            myName[ i ] = rhs.myName[ i ];//copy array into object
        produceCost = rhs.cost();  //assign the cost of rhs to this cost variable
        weight = rhs.getWeight(); //assign the weight of rhs to this weight variable
    }//end if

    return *this;//enables multiple assignment
}//end overloaded operator=

//cost function to return cost of canned good in cents
int Produce::cost() const
{
    return produceCost;//return the private variable cost
}//end member-function cost

//weight function to return the weight of produce in pounds
double Produce::getWeight() const
{
    return weight; //return the private variable weight
}//end member-function getWeight

//function to return name of the Item
const char* Produce::getName() const
{
    return myName;//return private variable myName
}//end function name()

//member-function to print the Produce
void Produce::print( ostream &out ) const
{
    cout << setw( NAME_WIDTH + COST_WIDTH ) << getWeight() << " lbs. @ " << cost() << " /lb." << ""
         << setfill(' ') << setw( NAME_WIDTH ) << getName() << "" 
         << setw ( COST_WIDTH ) << cost() * getWeight(); //output canned good's name followed by its cost

}//end member-function print  




Here is the last of it


checkout.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <iostream>
#include <iomanip>
using namespace std;

#include "defs.h"    // Specifies field widths for grocery receipt

#include "Item.h"
#include "CannedGood.h"
#include "Produce.h"
#include "Coupon.h"

int main()
{
    Item* items[100];   // Array of pointers to Items to checkout
    int numItems = 0;   // Number of Items added to the items array
    int totalCost = 0;  // Total cost of all the Items to checkout

    // Add Items to be checked out
    items[numItems++] = new Produce("Bananas", 5.3, 49);
    items[numItems++] = new CannedGood("Vegetable Soup",89);
    items[numItems++] = new Produce("Apples", 3.299, 109);
    items[numItems++] = new CannedGood("Green Beans",59);
    items[numItems++] = new CannedGood("Corn",49);
    items[numItems++] = new CannedGood("Baked Beans",79);
    items[numItems++] = new Produce("Watermelon", 11.303, 89);
    items[numItems++] = new CannedGood("Fruit Cocktail",45);
    items[numItems++] = new CannedGood("Tomato Soup",49);
    items[numItems++] = new Coupon("Vegetable Soup",10);
    items[numItems++] = new Coupon("Corn",15);

    // Output the grocery receipt header
    cout << "CSC234 Grocery Store" << endl
         << setfill('-') << setw(NAME_WIDTH + COST_WIDTH) << ""
         << setfill(' ')
         << endl << endl;

    // Print the Items on the grocery receipt
    for (int i = 0; i < numItems; ++i)
    {
        items[i]->print(cout);
        cout << endl << endl;

        // Add cost of current Item to total cost
        totalCost += items[i]->cost();
    }

    // Print out the total cost
    cout << left << setw(NAME_WIDTH) << "Total Cost"
         << right << fixed << setprecision(2)
         << setw(COST_WIDTH) << totalCost/100.0
         << endl;

	system("pause");
	return 0;
}


The program starts to run and outputs

CSC234 Grocery Store
---------------------
5.3 lbs. @ .49 / lb.=======(random stuff here) 259.7

and then it pops up a window that says
Unhandled exception at 0x0f59d51c (msvcr100d.dll) in Homework 3.exe: 0xC0000005: Access violation reading location 0xcdcdcdcd.
1
2
3
4
5
6
//default constructor for Item class 
Item::Item( const char* name )  
{  
	int nameSize = strlen(name);  
	char *myName = new char[nameSize + 1];// dynamically allocate space for char array myName based on size of name  
}//end default constructor   


Set a local variable nameSize equal to the number of letters in the c-string pointed to by name.
Allocate memory for a new string. Store the address of the memory in a local variable.

We fail to modify any members of the class in this constructor. We fail to keep a pointer to the allocated memory so it's leaked as soon as the constructor returns. We fail to do anything meaningful with the parameter name.

When we finally reach our destructor, the myName member of the class contains a random address that you're going to try to delete. That's probably not good.

You make the same mistakes throughout your code, so you'll be wanting to look in more than one place.

In the derived classes you add a member "char* myName" which has the same name and type as a member of the base class. Probably not something you want to do.

Your instructor should be shot for such a contrived example.

Topic archived. No new replies allowed.