PDA

View Full Version : problem using a copy constructor in c++




macman2790
Jul 14, 2007, 03:57 PM
I got an error message before i added the copy constructor saying"error no matching function for call to Item::Item", which means i need a copy constructor.the error happens at the line that the constructor is created for Inventory. also am i doing the right thing by assigning the public array inventory to the private array inventory, im not sure if it is ok. and on my copy constructor xcode is saying that those variables are not being used, why? Now the new error that xcode gives for the Inventory constructor, says "new types may not be defined as a return type." thats the main problem now.



#include <iostream>
using namespace std;

const int SIZE = 100;
class Item {
char *item;
double cost;
double retail;
int on_hand;
int lead_time;

public:
Item(char *item, double cost, double retail, int on_hand, int lead_time);
Item(const Item &obj);
void setItem(char *c){item = c;}
void setCost(double *d){cost = *d;}
void setRetail(double *d){retail = *d;}
void setOnHand(int *hand){on_hand = *hand;}
void setLeadTime(int *time){lead_time = *time;}
char *getItem(){return item;}
double getCost(){return cost;}
double getRetail(){return retail;}
int getOnHand(){return on_hand;}
int getLeadTime(){return lead_time;}
};
Item::Item(char *item, double cost, double retail, int on_hand, int lead_time){
this->item = item;
this->cost = cost;
this->retail = retail;
this->on_hand = on_hand;
this->lead_time = lead_time;
}
Item::Item(const Item &obj){
char *item = obj.item;
double cost = obj.cost;
double retail = obj.retail;
int on_hand = obj.on_hand;
int lead_time =obj.lead_time;
}

class Inventory {
Item invntry[SIZE];
char *name;
Inventory(char *name);
public:

char *getName(){return name;}
}
Inventory::Inventory(char *name){
this->name = name;
Item inventory[SIZE] = invntry;
}
int main () {
return 0;
}



thanks in advance



gnasher729
Jul 14, 2007, 04:22 PM
In the copy constructor for class Item, do you realize that you are copying the data from obj into a bunch of local variables, and that the "this" object will not be initialised in any way?

macman2790
Jul 14, 2007, 04:32 PM
In the copy constructor for class Item, do you realize that you are copying the data from obj into a bunch of local variables, and that the "this" object will not be initialised in any way?

i got rid of the copy constructor and it still says that error:new types may not be defined in a return type

lazydog
Jul 14, 2007, 04:45 PM
Hi

I've had a quick look through your code and I can see a few problems:-

In this copy constructor


Item::Item(const Item &obj){
char *item = obj.item;
double cost = obj.cost;
double retail = obj.retail;
int on_hand = obj.on_hand;
int lead_time =obj.lead_time;
}


you are declaring local variables when you should be setting the member variables.

A better way to write the constructors is like this:-


Item::Item(char *item, double cost, double retail, int on_hand, int lead_time)
: item( item ), cost( cost ), retail( retail ), on_hand( on_hand), lead_time( lead_time )
{
}

Item::Item(const Item &obj )
: item( obj.item ), cost( obj.cost ), retail( obj.retail ), on_hand( obj.on_hand), lead_time( obj.lead_time )
{
}



You also need a default constructor for Item, ie you need an Item::Item(). This is because the Inventory class defines an array of Items.

You also need a ; after the Inventory class definition.

There is also a problem in your Inventory constructor with regard to the member invntry. I'm not sure what you are trying to do but really you should be initialising invntry in the constructor instead of using its (uninitialised) value.

Hope this helps

b e n

macman2790
Jul 14, 2007, 09:47 PM
thanks


/Users/Kevin/Documents/Programming/Xcode/C++/Inventoryclass/main.cpp:57: error: expected unqualified-id before 'void'
/Users/Kevin/Documents/Programming/Xcode/C++/Inventoryclass/main.cpp:67: error: expected unqualified-id before 'void'
/Users/Kevin/Documents/Programming/Xcode/C++/Inventoryclass/main.cpp:90: error: expected declaration before '}' token

i know this is kinda long but please look at these three functions:

the first error is at: Inventory::void init_inv()
the second is at: Inventory::void menu();
the last error is at the last curly brace of the menu function.


#include <iostream>
using namespace std;

const int SIZE = 100;
class Item {
char *item;
double cost;
double retail;
int on_hand;
int lead_time;

public:
Item(char *item, double cost, double retail, int on_hand, int lead_time);
Item(const Item &obj);
Item();
void setItem(char *c){item = c;}
void setCost(double *d){cost = *d;}
void setRetail(double *d){retail = *d;}
void setOnHand(int *hand){on_hand = *hand;}
void setLeadTime(int *time){lead_time = *time;}
char *getItem(){return item;}
double getCost(){return cost;}
double getRetail(){return retail;}
int getOnHand(){return on_hand;}
int getLeadTime(){return lead_time;}
};
Item::Item(char *item, double cost, double retail, int on_hand, int lead_time){
this->item = item;
this->cost = cost;
this->retail = retail;
this->on_hand = on_hand;
this->lead_time = lead_time;
}
Item::Item(){
*item = '\0';
}


Item::Item(const Item &obj )
: item( obj.item ), cost( obj.cost ), retail( obj.retail ), on_hand( obj.on_hand), lead_time( obj.lead_time )
{
}

class Inventory {
Item inventory[SIZE];
char *name;
Inventory(char *name);
Inventory(const Inventory &obj);
public:
void init_inv(), enter(), update(), display(), menu(), input();
char *getName(){return name;}

};
Inventory::void init_inv(){

cout << "Enter name of the inventory: ";
cin >> name;

Inventory inv1(name);
for(int i = 0; i < SIZE; i++){
inventory[i].item = '\n';
}
}
Inventory::void menu(){
char choice;
for(;;){
do{
cout << "Choose one:\n\n";
cout << "(E)nter\n(D)isplay\n(U)pdate\nQuit\n";

}while(!strchr("eduq", tolower(ch));
cin >> choice;
switch(ch){
case 'E': enter();
break;
case 'U': update();
break;
case 'D': display();
break;
case 'Q':return;
}

}

}

}
Inventory::Inventory(char *name){
this->name = name;
Item inventory[SIZE] = inventory;
}
Inventory::Inventory(const Inventory &obj)
: name(obj.name), inventory(obj.inventory){
}
Inventory::void input(int i){
cout << "Item: ";
cin >> inventory[i].item;

cout << "Cost: ";
cin >> inventory[i].price;

cout << "Retail price: "
cin >> inventory[i].retail;

cout << "Quantity in stock: ";
cin >> inventory[i].on_hand;

cout << "Lead time before restock(in days): ";
cin >> inventory[i].lead_time;
}
Inventory::void enter(){
Item temp[SIZE+10];
int i;
for(i = 0; i < SIZE;i++){
if(!*inventory[i].item)
break;
}
if(i == size){
cout << "List full!\n";
return;
}
input(i);
}
Inventory::void update(){
char *item_search;
cout << "enter item to update:";
cin >> *item_search;

for(int i = 0; inventory[i].item;i++){
if(!strcmp(inventory[i].item, item_search)){
input(i);
char ch;
cout << "Search again? (y/n)";
if(choice == 'y' || choice == 'Y')
update();
else return;
}
else {
char choice;
cout << "Item not found. Search again? (y\n): ";
cin >> choice;
if(choice == 'y' || choice == 'Y')
update();
else return;
}
}

}
Inventory::void display(){
int t;
cout << "inventory name: ";
//sort();
for(t = 0; t < SIZE; t++){
if(*invntry[t].item){
cout << inventory[t].item << '\n';
cout << "Cost $" << invntry[t].cost << '\n';
cout << "Retail Price $" << invntry[t].retail;
cout << "\nOn hand: " << invntry[t].on_hand;
cout << "\nResupply time: ";
cout << invntry[t].lead_time << " days\n\n";
}
}

}

int main () {


init_inv();

return 0;
}

kpua
Jul 15, 2007, 01:39 AM
Change

Inventory::void menu()

to

void Inventory::menu()

and do the same to all the other function headers.

Think of the scope resolution as part of the name of the function, not a prefix to the whole declaration. The return type always comes before the name.

macman2790
Jul 15, 2007, 02:08 AM
ok i got all of that and i changed a lot of other things, like using the string class instead of char pointers, here is my revised code and i receive this error when trying to compile: /Users/Kevin/Documents/Programming/Xcode/C++/Inventoryclass/main.cpp:193: error: 'init_inv' was not declared in this scope




#include <iostream>
#include <string>
using std::string;
using namespace std;

const int SIZE = 100;
class Item {
string item;
double cost;
double retail;
int on_hand;
int lead_time;

public:
Item(string item, double cost, double retail, int on_hand, int lead_time){
item = item;
cost = cost;
retail = retail;
on_hand = on_hand;
lead_time = lead_time;
}
Item(const Item &obj);
Item();
void setItem(string c){item = c;}
void setCost(double d){cost = d;}
void setRetail(double d){retail = d;}
void setOnHand(int hand){on_hand = hand;}
void setLeadTime(int time){lead_time = time;}
string getItem(){return item;}
double getCost(){return cost;}
double getRetail(){return retail;}
int getOnHand(){return on_hand;}
int getLeadTime(){return lead_time;}


};
/*Item::Item(string item, double cost, double retail, int on_hand, int lead_time){
this->item = item;
this->cost = cost;
this->retail = retail;
this->on_hand = on_hand;
this->lead_time = lead_time;
}*/
Item::Item(){
item = '\0';
}
/*Item::Item(char *item, double cost, double retail, int on_hand, int lead_time)
: item( item ), cost( cost ), retail( retail ), on_hand( on_hand), lead_time( lead_time )
{
}*/

Item::Item(const Item &obj )
: item( obj.item ), cost( obj.cost ), retail( obj.retail ), on_hand( obj.on_hand), lead_time( obj.lead_time )
{
}

class Inventory {
Item inventory[SIZE];
string name;
Inventory(string name);
Inventory(const Inventory &obj);
public:
void init_inv(), enter(), update(), display(), menu(), input(int i);
string getName(){return name;}

};
Inventory::Inventory(string name){
name = name;
Item inventory[SIZE] = inventory;
}
Inventory::Inventory(const Inventory &obj)
: name(obj.name), inventory(obj.inventory){
}
void Inventory::init_inv(){

cout << "Enter name of the inventory: ";
cin >> name;

Inventory inv1 (name);


}
void Inventory::menu(){
char choice;
for(;;){
do{
cout << "Choose one:\n\n";
cout << "(E)nter\n(D)isplay\n(U)pdate\nQuit\n";
cin >> choice;
}while(!strchr("eduq", tolower(choice)));
}
switch(choice){
case 'E': enter();
break;
case 'U': update();
break;
case 'D': display();
break;
case 'Q':return;
}

}

void Inventory::input(int i){
cout << "Item: ";
string s;
cin >> s;
inventory[i].setItem(s);

cout << "Cost: ";
double c;
cin >> c;
inventory[i].setCost(c);

cout << "Retail price: ";
double r;
cin >> r;
inventory[i].setRetail(r);

cout << "Quantity in stock: ";
int q;
cin >> q;
inventory[i].setOnHand(q);

cout << "Lead time before restock(in days): ";
int lt;
cin >> lt;
inventory[i].setLeadTime(lt);
}
void Inventory::enter(){
//Item temp[SIZE+10];
int i;
for(i = 0; i < SIZE;i++){
if(inventory[i].getItem() == "\0")
break;
}
if(i == SIZE){
cout << "List full!\n";

return;
}
input(i);
}
void Inventory::update(){
string item_search;
cout << "enter item to update:";
cin >> item_search;
int i;
for(i = 0; i < SIZE;i++){
//Item it = inventory[i];
if(inventory[i].getItem() == item_search)break;
}
//input(i);
if(i == SIZE){
char choice;
cout << "Item not found. Search again? (y\n): ";
cin >> choice;
if(choice == 'y' || choice == 'Y')
update();
else return;
}
input(i);
char choice;
cout << "Search again? (y/n)";
if(choice == 'y' || choice == 'Y')
update();
else return;





}
void Inventory::display(){
int t;
cout << "inventory name: ";

for(t = 0; t < SIZE; t++){
cout << inventory[t].getItem() << '\n';
cout << "Cost $" << inventory[t].getCost() << '\n';
cout << "Retail Price $" << inventory[t].getRetail();
cout << "\nOn hand: " << inventory[t].getOnHand();
cout << "\nResupply time: ";
cout << inventory[t].getLeadTime() << " days\n\n";
}


}

int main () {

init_inv();

return 0;
}




notice that im using the init_inv() function as the only function in main.

lazydog
Jul 15, 2007, 04:20 AM
hi

You have the error because you are trying to call an instance method of the Inventory class. In other words you need to create an Inventory object before you can call its init_v() method. Try something like this:-


int main () {

Inventory inv( "fish" ) ;
inv.init_inv();

return 0;
}


However before that will work you will need to make your constructors public. At the moment the constructors for Inventory are private so you need to give them public access rights:-


class Inventory {
Item inventory[SIZE];
string name;
public:
Inventory(string name);
Inventory(const Inventory &obj);
public:
void init_inv(), enter(), update(), display(), menu(), input(int i);
string getName(){return name;}

};


Your code will then compile… however I'm not sure it will do what you intend it to do. For example, your init_inv() method creates a local Inventory object which seems a bit redundant:-


void Inventory::init_inv(){

cout << "Enter name of the inventory: ";
cin >> name;

Inventory inv1 (name);
}


Are you trying to create a factory method? If so init_inv() should be made a class method something like this:-


class Inventory
{


public: static Inventory* init_inv() ;

};

Inventory* Inventory::init_inv()
{
std::string name ;
cout << "Enter name of the inventory: ";
cin >> name;

return new Inventory(name);
}

int main ()
{

Inventory* inv = Inventory::init_inv();

return 0;
}


Hope this helps.

b e n

macman2790
Jul 15, 2007, 12:10 PM
thanks ben
hi

You have the error because you are trying to call an instance method of the Inventory class. In other words you need to create an Inventory object before you can call its init_v() method. Try something like this:-


int main () {

Inventory inv( "fish" ) ;
inv.init_inv();

return 0;
}


However before that will work you will need to make your constructors public. At the moment the constructors for Inventory are private so you need to give them public access rights:-


class Inventory {
Item inventory[SIZE];
string name;
public:
Inventory(string name);
Inventory(const Inventory &obj);
public:
void init_inv(), enter(), update(), display(), menu(), input(int i);
string getName(){return name;}

};


Your code will then compile… however I'm not sure it will do what you intend it to do. For example, your init_inv() method creates a local Inventory object which seems a bit redundant:-


void Inventory::init_inv(){

cout << "Enter name of the inventory: ";
cin >> name;

Inventory inv1 (name);
}


Are you trying to create a factory method? If so init_inv() should be made a class method something like this:-


class Inventory
{


public: static Inventory* init_inv() ;

};

Inventory* Inventory::init_inv()
{
std::string name ;
cout << "Enter name of the inventory: ";
cin >> name;

return new Inventory(name);
}

int main ()
{

Inventory* inv = Inventory::init_inv();

return 0;
}


Hope this helps.

b e n
when i use that gdb runs and i get a signal 11 (SIGSEV)
anyone know why?

lazydog
Jul 15, 2007, 01:45 PM
Hi
If you post your complete code I'll try running it.

b e n

gnasher729
Jul 15, 2007, 05:22 PM
i got rid of the copy constructor and it still says that error:new types may not be defined in a return type

Do you realize that in the constructor for class Inventory you make exactly the same mistake?

Apart from that, you cannot use a constructor with arguments to initialise an array. Take a moment to think what that would mean. And since you wrote a non-default constructor, your default constructor is officially gone.

macman2790
Jul 16, 2007, 03:16 AM
Hi
If you post your complete code I'll try running it.

b e n

here is the complete code that isnt working.




#include <iostream>
#include <string>
using std::string;
using namespace std;

const int SIZE = 100;

class Item {
string item;
double cost;
double retail;
int on_hand;
int lead_time;

public:
Item(string item, double cost, double retail, int on_hand, int lead_time){
item = item;
cost = cost;
retail = retail;
on_hand = on_hand;
lead_time = lead_time;
}
Item(const Item &obj);
Item();
void setItem(string c){item = c;}
void setCost(double d){cost = d;}
void setRetail(double d){retail = d;}
void setOnHand(int hand){on_hand = hand;}
void setLeadTime(int time){lead_time = time;}
string getItem(){return item;}
double getCost(){return cost;}
double getRetail(){return retail;}
int getOnHand(){return on_hand;}
int getLeadTime(){return lead_time;}
//friend void init_inv();
//friend void init_inv(), enter(), update(), display(), menu(), input(int i);

};

Item::Item(){
item = "\0";
}


Item::Item(const Item &obj )
: item( obj.item ), cost( obj.cost ), retail( obj.retail ), on_hand( obj.on_hand), lead_time( obj.lead_time )
{
}

class Inventory {

Item inventory[SIZE];
string name;
public:
Inventory(string name);
Inventory();
Inventory(const Inventory &obj);
public:
static Inventory *init_inv();
void enter(), update(), display(), menu(), input(int i);
string getName(){return name;}

};
Inventory::Inventory(){}
Inventory::Inventory(string name){
name = name;
Item inventory[SIZE] = inventory;
}
Inventory::Inventory(const Inventory &obj)
: name(obj.name), inventory(obj.inventory){
}
/*void Inventory::init_inv(){

cout << "Enter name of the inventory: ";
cin >> name;

Inventory inv1 (name);


}*/
Inventory *Inventory::init_inv()
{
std::string name ;
cout << "Enter name of the inventory: ";
cin >> name;

return new Inventory(name);
}

void Inventory::menu(){
char choice;
for(;;){
do{
cout << "Choose one:\n\n";
cout << "(E)nter\n(D)isplay\n(U)pdate\nQuit\n";
cin >> choice;
}while(!strchr("eduq", tolower(choice)));
}
switch(choice){
case 'E': enter();
break;
case 'U': update();
break;
case 'D': display();
break;
case 'Q':return;
}

}

void Inventory::input(int i){
cout << "Item: ";
string s;
cin >> s;
inventory[i].setItem(s);

cout << "Cost: ";
double c;
cin >> c;
inventory[i].setCost(c);

cout << "Retail price: ";
double r;
cin >> r;
inventory[i].setRetail(r);

cout << "Quantity in stock: ";
int q;
cin >> q;
inventory[i].setOnHand(q);

cout << "Lead time before restock(in days): ";
int lt;
cin >> lt;
inventory[i].setLeadTime(lt);
}
void Inventory::enter(){
int i;
for(i = 0; i < SIZE;i++){
if(inventory[i].getItem() == "\0")
break;
}
if(i == SIZE){
cout << "List full!\n";

return;
}
input(i);
}
void Inventory::update(){
string item_search;
cout << "enter item to update:";
cin >> item_search;
int i;
for(i = 0; i < SIZE;i++){
if(inventory[i].getItem() == item_search)break;
}
if(i == SIZE){
char choice;
cout << "Item not found. Search again? (y\n): ";
cin >> choice;
if(choice == 'y' || choice == 'Y')
update();
else return;
}
input(i);
char choice;
cout << "Search again? (y/n)";
if(choice == 'y' || choice == 'Y')
update();
else return;





}
void Inventory::display(){
int t;
cout << "inventory name: ";

for(t = 0; t < SIZE; t++){
cout << inventory[t].getItem() << '\n';
cout << "Cost $" << inventory[t].getCost() << '\n';
cout << "Retail Price $" << inventory[t].getRetail();
cout << "\nOn hand: " << inventory[t].getOnHand();
cout << "\nResupply time: ";
cout << inventory[t].getLeadTime() << " days\n\n";
}


}

int main () {
Inventory* inv = Inventory::init_inv();

return 0;
}

lazydog
Jul 16, 2007, 04:02 AM
Like gnasher729 said, your constructor has an error… see the line I commented out below.


Inventory::Inventory(string name)
{
name = name;
//Item inventory[SIZE] = inventory;
}


The code should compile now at least. I added a display() to your main() function so that you can see that default items are being created.


int main ()
{
Inventory* inv = Inventory::init_inv();

inv->display() ;

return 0;
}


However, I think you've got a long way to go before your program does what you want!

good luck

b e n

macman2790
Jul 16, 2007, 04:37 AM
Like gnasher729 said, your constructor has an error… see the line I commented out below.


Inventory::Inventory(string name)
{
name = name;
//Item inventory[SIZE] = inventory;
}


The code should compile now at least. I added a display() to your main() function so that you can see that default items are being created.


int main ()
{
Inventory* inv = Inventory::init_inv();

inv->display() ;

return 0;
}


However, I think you've got a long way to go before your program does what you want!

good luck

b e n


thank you so much.

macman2790
Jul 16, 2007, 11:12 AM
one more very trivial problem. when i use the getName() funciton in a cout statement, it doesn't print anything. anyone know why?

lazydog
Jul 16, 2007, 02:10 PM
The constructor:-


Inventory::Inventory(string name){
name = name;
//Item inventory[SIZE] = inventory;
}


is just setting the parameter 'name' to itself. I think you meant to do:-


Inventory::Inventory(string name)
{
this->name = name;
}

or

Inventory::::Inventory(string name)
: name( name )
{
}



Perhaps now would be a good time to adopt some sort of naming convention! For example you can name all you class member variables with a leading 'm' or a trailing '_':-


class Inventory {

Item inventory_[SIZE];
string name_;
public:
Inventory(string name);
Inventory();
Inventory(const Inventory &obj);
public:
static Inventory *init_inv();
void enter(), update(), display(), menu(), input(int i);
string getName(){return name_;}

};


This will help avoid some of the mistakes you've been making.

b e n

MarkCollette
Jul 17, 2007, 04:30 PM
Same thing with:

Item(string item, double cost, double retail, int on_hand, int lead_time){
item = item;
cost = cost;
retail = retail;
on_hand = on_hand;
lead_time = lead_time;
}


Method parameters have more precedence in scope than class instance fields, so doing item = item means that the method parameter is being assigned to itself, which may lead to corruption for complex objects. And, your object's actual fields are still unset.

What you want is:

Item(string i, double c, double r, int oh, int lt) :
item(i), cost(c), retail(r), on_hand(oh), lead_time(lt)
{
}


This is better than doing:

Item(string i, double c, double r, int oh, int lt) {
item = i;
cost = c;
retail = r;
on_hand = oh;
lead_time = lt;
}


Because the latter form will actually call the default constructor for each class instance field first, and then do the line by line assignments, which is inefficient. Plus, that means that item(i) will be using string's constructor that takes a string parameter, whereas item = i will be first using string's default constructor, and then the assignment operator that takes a string argument. That can lead to pointless reallocations of the underlying char[] inside the string.