Hello programmers!

I have been working on a hardware store application, where there is a HardwareRecordclass that stores information about each object in a store (ex: nuts, bolts, screws, and so forth).

Here's my declaration of this class:

//  HardwareRecord.h
//  Initialize Hardware Store File
//
//
//  Definition of HardwareRecord class

#ifndef __Initialize_Hardware_Store_File__HardwareRecord__
#define __Initialize_Hardware_Store_File__HardwareRecord__

#include <iostream>

class HardwareRecord
{


public:

     HardwareRecord(int=0,std::string="",std::string="",double=0.); //constructor
    explicit HardwareRecord();
    HardwareRecord operator=(HardwareRecord&);

    //'set' and 'get' functions
    void setAccountNumber(int);
    int getAccountNumber() const;

    void setName(std::string);
    std::string getName() const;

    void setPrice(double);
    double getPrice() const;

    void setDescription(std::string);
    std::string getDescription() const;

    void wipeRecord(); //set everything to blank


private:
    int myAccountNumber;
    std::string myName;
    std::string myDescription;
    double myPrice;
};

#endif /* defined(__Initialize_Hardware_Store_File__HardwareRecord__) */

As you can see, this class relies on four private members: myAccountNumber, myName, myDescription, and myPrice. I have declared two constructors- one that sets the values of each of those members, and another that sets each member to default values.

Here's how the class is defined (in a .cpp file):

//  Implementation of HardwareRecord class definition

#include <iostream>
#include <string>
#include <cstdlib>
#include "HardwareRecord.h"

using namespace std;

HardwareRecord HardwareRecord::operator=(HardwareRecord & aRecord)
{
    this->myAccountNumber=aRecord.myAccountNumber;
    this->myName=aRecord.myName;
    this->myDescription=aRecord.myDescription;
    this->myPrice=aRecord.myPrice;

    return *this; //allow for cascaded overloading
}

HardwareRecord::HardwareRecord(int account,string name,string description, double price)
{
    setAccountNumber(account);
    setName(name);
    setPrice(price);
    setDescription(description);
}

HardwareRecord::HardwareRecord()
{
    setAccountNumber(0);
    setName("");
    setPrice(0);
    setDescription("");
}


void HardwareRecord::wipeRecord()
{
    setAccountNumber(0);
    setName("");
    setPrice(0);
    setDescription("");
}

void HardwareRecord::setAccountNumber(int num)
{
    if (num < 0)
    {
        throw invalid_argument("The account number is not in the valid range (greater or equal to 0)");
    }
    else
    {
        myAccountNumber=num;
    }
}

int HardwareRecord::getAccountNumber() const
{
    return myAccountNumber;
}

void HardwareRecord::setName(string name)
{

   myName=name;

}

string HardwareRecord::getName() const
{
    return myName;
}

void HardwareRecord::setPrice(double price)
{
    if (price < 0)
    {
        throw invalid_argument("The price can not be less than zero");
    }
    else
    {
        myPrice=price;
    }
}

double HardwareRecord::getPrice() const
{
    return myPrice;
}

void HardwareRecord::setDescription(string description)
{
    this->myDescription=description;
}

string HardwareRecord::getDescription() const
{
    return myDescription;
}

The point of the class is to be used in a random-access file setting, where a .dat file has 100 HardwareRecords (written out in binary) to store information about the store. However, when I try to create a temporary variable: HardwareRecord temp;, the error pops up: No matching constructor for initialization of 'HardwareRecord'. Here's how it is used:

//  Application that models a store's record of inventory

#include <iostream>
#include <fstream>
#include <iomanip>
#include <cstdlib>
#include <sstream>
#include "HardwareRecord.h" //HardwareRecord definition
using namespace std;

//enumeration of choices
enum Choices {WIPE_RECORDS,UPDATE,LIST,PRINT,DELETE,NEW,END,LAST};

std::ostream& operator<<(std::ostream& op,const Choices& choices)
{
    //print the string corresponding to the value of enum type Choices
    string output="";
    switch (choices)
    {
        case WIPE_RECORDS:
            output = "wipe records";
            break;

        case UPDATE:
            output = "update records";
            break;

        case LIST:
            output = "list records";
            break;

        case PRINT:
            output = "print records";
            break;

        case DELETE:
            output = "delete records";
            break;

        case NEW:
            output = "add new record";
            break;

        case END:
            output = "terminate application";
            break;

        case LAST:
            output = "an option used to iterate over the values in the Choice enumeration";
            break;

        default:
            cerr << "Error. invalid value is read";
            exit(EXIT_FAILURE);
            break;


    }

    op << output; //print output
    return op;
}

//prototype of helper functions
int enterChoice();
void wipeRecords(fstream&);
void updateRecord(fstream&);
void listRecords(fstream&);
void createTextFile(fstream&);
void deleteRecord(fstream&);
void newRecord(fstream&);

int main()
{
    //open file for reading and writinbg
    fstream outRecord ("HardwareRecord.dat",ios::in|ios::out|ios::binary);

    //exit program if fstream cannot open file
    if (!outRecord)
    {
        cerr << "File could not be opened." << endl;
        exit(EXIT_FAILURE);
    }

    int choice; //user's choice

    //enable user to specify action
    while ((choice=enterChoice()) !=END)
    {
        switch (choice)
        {
            case WIPE_RECORDS: //wipe all records clean
                wipeRecords(outRecord);
                break;

            case UPDATE: //update a record
                updateRecord(outRecord);
                break;

            case LIST: //list all current records
                listRecords(outRecord);
                break;

            case PRINT: //print a record
                createTextFile(outRecord);
                break;

            case DELETE: //delete a record
                deleteRecord(outRecord);
                break;

            case NEW: //add a new record (if space allows)
                newRecord(outRecord);
                break;

            default: //display error if user does not select valid choice
                cerr << "Incorrect choice" << endl;
        }

        outRecord.clear();
    }
    return 0;
}

//enable user to input menu choice
int enterChoice()
{
    //display avaliable options
    cout << "\nEnter your choice:\n"<< endl;
    Choices aChoice;
    for (int c=WIPE_RECORDS; c < LAST; c++)
    {
        aChoice= (Choices) c;
        cout << c << " - " << aChoice << endl;
    }
    cout << "\n?: ";
    int menuChoice;
    cin >> menuChoice;
    return menuChoice;

}

void wipeRecords(fstream& theFile)
{
    HardwareRecord temp; //---THIS IS THE LINE THAT IS CAUSING THE ERROR!!
    for (int i=0; i < 100;i++)
    {
        //convert record from binary and assign to temp
        //make temp "wipe itself"
    }
}

I realize that a lot of the functions that are defined as prototypes are not given their respective definitions (yet, but I will define them as soon as I can get this problem sorted out).
If you look to the last few lines, you will see the line that is causing the error (I commented it with caps lock for your convenience).

What is going on?
Why am I getting the error?

Thanks in advance!

change line 18 HardwareRecord(int=0,std::string="",std::string="",double=0.); to HardwareRecord(int account=0,string name="",string description="", double price=0.0);. That should fix it.

Nope. It did not fix it.

Here's what is going on now:

//  Definition of HardwareRecord class

#ifndef __Initialize_Hardware_Store_File__HardwareRecord__
#define __Initialize_Hardware_Store_File__HardwareRecord__

#include <iostream>

class HardwareRecord
{


public:

    HardwareRecord(int account=0,std::string name="",std::string description="", double price=0.0); //constructor
    explicit HardwareRecord();
    HardwareRecord operator=(HardwareRecord&);

    //'set' and 'get' functions
    void setAccountNumber(int);
    int getAccountNumber() const;

    void setName(std::string);
    std::string getName() const;

    void setPrice(double);
    double getPrice() const;

    void setDescription(std::string);
    std::string getDescription() const;

    void wipeRecord(); //set everything to blank


private:
    int myAccountNumber;
    std::string myName;
    std::string myDescription;
    double myPrice;
};

#endif /* defined(__Initialize_Hardware_Store_File__HardwareRecord__) */

I changed my HardewareRecord header file definition (line 18) as you suggested, and it did not work. I still get the same error in the same spot.

HardwareRecord temp;

It doesn't know which constructor you mean to use to make this object. The default one (HardwareRecord::HardwareRecord()), or the one that takes four parameters that all have default values.

Looks like the easiest fix is to remove the default constructor.

Edited 2 Years Ago by Moschops

Yeah I was just reading up on that. If a constructor has all default paramaters in the initialization section then it is treated as a default constructor.

I removed it, and I still get the no matching constructor message.

Here's the code:

Header File

    //  HardwareRecord.h
    //  Initialize Hardware Store File
    //
    //  Created by ------- ------- on 5/18/14.
    //  Copyright (c) 2014 ------- --------. All rights reserved.
    //
    //  Definition of HardwareRecord class



#ifndef __Initialize_Hardware_Store_File__HardwareRecord__
#define __Initialize_Hardware_Store_File__HardwareRecord__

#include <iostream>

class HardwareRecord
{


public:

    HardwareRecord(int account=0,std::string name="",std::string description="", double price=0.0); //constructor
    HardwareRecord operator=(HardwareRecord&); //assignment operator

    //'set' and 'get' functions
    void setAccountNumber(int);
    int getAccountNumber() const;

    void setName(std::string);
    std::string getName() const;

    void setPrice(double);
    double getPrice() const;

    void setDescription(std::string);
    std::string getDescription() const;

    void wipeRecord(); //set everything to blank


private:
    int myAccountNumber;
    std::string myName;
    std::string myDescription;
    double myPrice;
};

#endif /* defined(__Initialize_Hardware_Store_File__HardwareRecord__) */

Implementation of HardwareRecord class

//
//  HardwareRecord.cpp
//  Initialize Hardware Store File
//
//  Created by Nathan Pavlovsky on 5/18/14.
//  Copyright (c) 2014 Nathan Pavlovsky. All rights reserved.
//
//  Implementation of HardwareRecord class definition

#include <iostream>
#include <string>
#include <cstdlib>
#include "HardwareRecord.h"

using namespace std;

HardwareRecord HardwareRecord::operator=(HardwareRecord & aRecord)
{
    this->myAccountNumber=aRecord.myAccountNumber;
    this->myName=aRecord.myName;
    this->myDescription=aRecord.myDescription;
    this->myPrice=aRecord.myPrice;

    return *this; //allow for cascaded overloading
}

HardwareRecord::HardwareRecord(int account,string name,string description, double price)
{
    setAccountNumber(account);
    setName(name);
    setPrice(price);
    setDescription(description);
}



void HardwareRecord::wipeRecord()
{
    setAccountNumber(0);
    setName("");
    setPrice(0);
    setDescription("");
}

void HardwareRecord::setAccountNumber(int num)
{
    if (num < 0)
    {
        throw invalid_argument("The account number is not in the valid range (greater or equal to 0)");
    }
    else
    {
        myAccountNumber=num;
    }
}

int HardwareRecord::getAccountNumber() const
{
    return myAccountNumber;
}

void HardwareRecord::setName(string name)
{

   myName=name;

}

string HardwareRecord::getName() const
{
    return myName;
}

void HardwareRecord::setPrice(double price)
{
    if (price < 0)
    {
        throw invalid_argument("The price can not be less than zero");
    }
    else
    {
        myPrice=price;
    }
}

double HardwareRecord::getPrice() const
{
    return myPrice;
}

void HardwareRecord::setDescription(string description)
{
    this->myDescription=description;
}

string HardwareRecord::getDescription() const
{
    return myDescription;
}

main.cpp: I realize that many of the function prototypes are not defined, but I will do that once this problem is fixed.

//  Application that models a store's record of inventory

#include <iostream>
#include <fstream>
#include <iomanip>
#include <cstdlib>
#include <sstream>
#include "HardwareRecord.h" //HardwareRecord definition
using namespace std;

//enumeration of choices
enum Choices {WIPE_RECORDS,UPDATE,LIST,PRINT,DELETE,NEW,END,LAST};

std::ostream& operator<<(std::ostream& op,const Choices& choices)
{
    //print the string corresponding to the value of enum type Choices
    string output="";
    switch (choices)
    {
        case WIPE_RECORDS:
            output = "wipe records";
            break;

        case UPDATE:
            output = "update records";
            break;

        case LIST:
            output = "list records";
            break;

        case PRINT:
            output = "print records";
            break;

        case DELETE:
            output = "delete records";
            break;

        case NEW:
            output = "add new record";
            break;

        case END:
            output = "terminate application";
            break;

        case LAST:
            output = "an option used to iterate over the values in the Choice enumeration";
            break;

        default:
            cerr << "Error. invalid value is read";
            exit(EXIT_FAILURE);
            break;


    }

    op << output; //print output
    return op;
}

//prototype of helper functions
int enterChoice();
void wipeRecords(fstream&);
void updateRecord(fstream&);
void listRecords(fstream&);
void createTextFile(fstream&);
void deleteRecord(fstream&);
void newRecord(fstream&);

int main()
{
    //open file for reading and writinbg
    fstream outRecord ("HardwareRecord.dat",ios::in|ios::out|ios::binary);

    //exit program if fstream cannot open file
    if (!outRecord)
    {
        cerr << "File could not be opened." << endl;
        exit(EXIT_FAILURE);
    }

    int choice; //user's choice

    //enable user to specify action
    while ((choice=enterChoice()) !=END)
    {
        switch (choice)
        {
            case WIPE_RECORDS: //wipe all records clean
                wipeRecords(outRecord);
                break;

            case UPDATE: //update a record
                updateRecord(outRecord);
                break;

            case LIST: //list all current records
                listRecords(outRecord);
                break;

            case PRINT: //print a record
                createTextFile(outRecord);
                break;

            case DELETE: //delete a record
                deleteRecord(outRecord);
                break;

            case NEW: //add a new record (if space allows)
                newRecord(outRecord);
                break;

            default: //display error if user does not select valid choice
                cerr << "Incorrect choice" << endl;
        }

        outRecord.clear();
    }
    return 0;
}

//enable user to input menu choice
int enterChoice()
{
    //display avaliable options
    cout << "\nEnter your choice:\n"<< endl;
    Choices aChoice;
    for (int c=WIPE_RECORDS; c < LAST; c++)
    {
        aChoice= (Choices) c;
        cout << c << " - " << aChoice << endl;
    }
    cout << "\n?: ";
    int menuChoice;
    cin >> menuChoice;
    return menuChoice;

}

void wipeRecords(fstream& theFile)
{
    HardwareRecord temp; //still get the error here
    for (int i=0; i < 100;i++)
    {
        //convert record from binary and assign to temp
        //make temp "wipe itself"
    }
}

As you can see, I removed the default constructor, and nothing is happening.
What to do now?

I added the default values to the definition as following:
HardwareRecord::HardwareRecord(int account=0,string name="",string description="", double price=0),

and I got a new error "Redefinition of default argument". As far as I remember, this is not supposed to happen, only the header file contains the definition for a constructor's default values.

You are correct about the default values. I normally just write my constructors that are defaults in the .h file.

I put the code that you last posted in MSVS 2013 express and it compiled and entered the function correctly. I enven turned wipeRecords() into the following to make sure I had a valid object.

void wipeRecords(fstream& theFile)
{
    HardwareRecord temp; //still get the error here
    temp.setPrice(10.52);
    cout << temp.getPrice() << endl;
    for (int i = 0; i < 100; i++)
    {
        //convert record from binary and assign to temp
        //make temp "wipe itself"
    }
}

I did have to comment out all of the function calls that you haven't declared yet for it to link correctly.

Something is going wrong.

Here is what I have:

My header file:

    //
    //  HardwareRecord.h
    //  Initialize Hardware Store File
    //
    //  Created by Nathan Pavlovsky on 5/18/14.
    //  Copyright (c) 2014 Nathan Pavlovsky. All rights reserved.
    //
    //  Definition of HardwareRecord class



#ifndef __Initialize_Hardware_Store_File__HardwareRecord__
#define __Initialize_Hardware_Store_File__HardwareRecord__

#include <iostream>

class HardwareRecord
{


public:

    HardwareRecord(int account=0,std::string name="",std::string description="", double price=0.0); //constructor
    HardwareRecord operator=(HardwareRecord&);

    //'set' and 'get' functions
    void setAccountNumber(int);
    int getAccountNumber() const;

    void setName(std::string);
    std::string getName() const;

    void setPrice(double);
    double getPrice() const;

    void setDescription(std::string);
    std::string getDescription() const;

    void wipeRecord(); //set everything to blank


private:
    int myAccountNumber;
    std::string myName;
    std::string myDescription;
    double myPrice;
};

#endif /* defined(__Initialize_Hardware_Store_File__HardwareRecord__) */

Class definition:

//
//  HardwareRecord.cpp
//  Initialize Hardware Store File
//
//  Created by Nathan Pavlovsky on 5/18/14.
//  Copyright (c) 2014 Nathan Pavlovsky. All rights reserved.
//
//  Implementation of HardwareRecord class definition

#include <iostream>
#include "HardwareRecord.h"

using namespace std;

HardwareRecord HardwareRecord::operator=(HardwareRecord & aRecord)
{
    this->myAccountNumber=aRecord.myAccountNumber;
    this->myName=aRecord.myName;
    this->myDescription=aRecord.myDescription;
    this->myPrice=aRecord.myPrice;

    return *this; //allow for cascaded overloading
}

HardwareRecord::HardwareRecord(int account,string name,string description, double price)
{
    setAccountNumber(account);
    setName(name);
    setPrice(price);
    setDescription(description);
}



void HardwareRecord::wipeRecord()
{
    setAccountNumber(0);
    setName("");
    setPrice(0);
    setDescription("");
}

void HardwareRecord::setAccountNumber(int num)
{
    if (num < 0)
    {
        throw invalid_argument("The account number is not in the valid range (greater or equal to 0)");
    }
    else
    {
        myAccountNumber=num;
    }
}

int HardwareRecord::getAccountNumber() const
{
    return myAccountNumber;
}

void HardwareRecord::setName(string name)
{

   myName=name;

}

string HardwareRecord::getName() const
{
    return myName;
}

void HardwareRecord::setPrice(double price)
{
    if (price < 0)
    {
        throw invalid_argument("The price can not be less than zero");
    }
    else
    {
        myPrice=price;
    }
}

double HardwareRecord::getPrice() const
{
    return myPrice;
}

void HardwareRecord::setDescription(string description)
{
    this->myDescription=description;
}

string HardwareRecord::getDescription() const
{
    return myDescription;
}

My main file.

//
//  main.cpp
//  HardwareStoreApplication
//
//  Created by Nathan Pavlovsky on 6/17/14.
//  Copyright (c) 2014 Nathan Pavlovsky. All rights reserved.
//
//  Application that models a store's record of inventory

#include <iostream>
#include <fstream>
#include <iomanip>
#include <cstdlib>
#include <sstream>
#include "HardwareRecord.h" //HardwareRecord definition
using namespace std;

//enumeration of choices
enum Choices {WIPE_RECORDS,UPDATE,LIST,PRINT,DELETE,NEW,END,LAST};

std::ostream& operator<<(std::ostream& op,const Choices& choices)
{
    //print the string corresponding to the value of enum type Choices
    string output="";
    switch (choices)
    {
        case WIPE_RECORDS:
            output = "wipe records";
            break;

        case UPDATE:
            output = "update records";
            break;

        case LIST:
            output = "list records";
            break;

        case PRINT:
            output = "print records";
            break;

        case DELETE:
            output = "delete records";
            break;

        case NEW:
            output = "add new record";
            break;

        case END:
            output = "terminate application";
            break;

        case LAST:
            output = "an option used to iterate over the values in the Choice enumeration";
            break;

        default:
            cerr << "Error. invalid value is read";
            exit(EXIT_FAILURE);
            break;


    }

    op << output; //print output
    return op;
}

//prototype of helper functions
int enterChoice();
void wipeRecords(fstream&);
void updateRecord(fstream&);
void listRecords(fstream&);
void createTextFile(fstream&);
void deleteRecord(fstream&);
void newRecord(fstream&);

int main()
{
    //open file for reading and writinbg
    fstream outRecord ("HardwareRecord.dat",ios::in|ios::out|ios::binary);

    //exit program if fstream cannot open file
    if (!outRecord)
    {
        cerr << "File could not be opened." << endl;
        exit(EXIT_FAILURE);
    }

    int choice; //user's choice

    //enable user to specify action
    while ((choice=enterChoice()) !=END)
    {
        switch (choice)
        {
            case WIPE_RECORDS: //wipe all records clean
                wipeRecords(outRecord);
                break;

            case UPDATE: //update a record
                updateRecord(outRecord);
                break;

            case LIST: //list all current records
                listRecords(outRecord);
                break;

            case PRINT: //print a record
                createTextFile(outRecord);
                break;

            case DELETE: //delete a record
                deleteRecord(outRecord);
                break;

            case NEW: //add a new record (if space allows)
                newRecord(outRecord);
                break;

            default: //display error if user does not select valid choice
                cerr << "Incorrect choice" << endl;
        }

        outRecord.clear();
    }
    return 0;
}

//enable user to input menu choice
int enterChoice()
{
    //display avaliable options
    cout << "\nEnter your choice:\n"<< endl;
    Choices aChoice;
    for (int c=WIPE_RECORDS; c < LAST; c++)
    {
        aChoice= (Choices) c;
        cout << c << " - " << aChoice << endl;
    }
    cout << "\n?: ";
    int menuChoice;
    cin >> menuChoice;
    return menuChoice;

}

void wipeRecords(fstream& theFile)
{
    HardwareRecord temp; //I STILL GET THE ERROR RIGHT HERE
    for (int i=0; i < 100;i++)
    {
        //convert record from binary and assign to temp
        //make temp "wipe itself"
    }
}

I still get the error, even though I did default values and I removed my definition of the default constructor. Could you show what you have done to my code so I could see why it compiled? Maybe you did something different, and you don't even know it.

Okay I compiled this on my machine at home running MSVS 2012 Ultimate. As I mentioned earlier I had to comment out the functions called in main that were not defined yet to get it to link. I am attaching the files to this so you can see how I have each file. I had to put them in a zip file to attach them.

Edited 2 Years Ago by NathanOliver

Nothing happened. I even copied and pasted all the contents of your files into mine, and it did not compile. Something funky platform-wise is going on.

I am doing this on my xCode program for mac (Version 5.0.2 (5A3005)). I never had this situation before. Is there a problem that apple needs to know about.

I think you can really clean up your code still and simplify it lots ...

Take a look at this and see the added comments ...

file: HardwareRecord.h

// file: HardwareRecord.h //

#ifndef HARDWARE_RECORD_H
#define HARDWARE_RECORD_H

#include <iostream>

class HardwareRecord
{
public:
    //constructor
    HardwareRecord( int account =0, std::string name ="",
                       std::string description ="",
                       double price =0.0 );

    // default copy ctor... is ok here ...
    //HardwareRecord operator = ( const HardwareRecord& );

    // 'set' and 'get' functions
    void setAccountNumber(size_t);
    size_t getAccountNumber() const;

    void setName(std::string);
    std::string getName() const;

    void setPrice(double);
    double getPrice() const;

    void setDescription(std::string);
    std::string getDescription() const;

    void wipeRecord(); //set everything to blank

private:
    size_t myAccountNumber;
    std::string myName;
    std::string myDescription;
    double myPrice;
};

#endif

file HardwareRecord.cpp

//  file HardwareRecord.cpp

#include <stdexcept>      // std::invalid_argument

#include "HardwareRecord.h"
// #include <iostream> // included above

using std::string;
using std::invalid_argument;

/* default copy ctor... is ok here ...
HardwareRecord HardwareRecord::operator= ( const HardwareRecord& aRecord )
{
    myAccountNumber=aRecord.myAccountNumber;
    myName=aRecord.myName;
    myDescription=aRecord.myDescription;
    myPrice=aRecord.myPrice;

    return *this; //allow for cascaded overloading
}
*/

HardwareRecord::HardwareRecord( int account, string name,
                                string description,
                                double price )
    : myAccountNumber(account), myName(name),
    myDescription(description), myPrice(price)
{
    /* *** NO ***
    setAccountNumber(account);
    setName(name);
    setPrice(price);
    setDescription(description);
    */
}



void HardwareRecord::wipeRecord()
{
    setAccountNumber(0);
    setName("");
    setPrice(0);
    setDescription("");
}

void HardwareRecord::setAccountNumber(size_t num)
{
    /*
    if (num < 0)
    {
        throw invalid_argument("The account number is not in the valid range (greater or equal to 0)");
    }
    else
    {*/
        myAccountNumber = num;
    //}
}

size_t HardwareRecord::getAccountNumber() const
{
    return myAccountNumber;
}

void HardwareRecord::setName(string name)
{

   myName=name;

}

string HardwareRecord::getName() const
{
    return myName;
}

void HardwareRecord::setPrice(double price)
{
    if (price < 0)
    {
        throw invalid_argument( "\nThe price can not "
                                "be less than zero.\n" );
    }
    else
    {
        myPrice = price;
    }
}

double HardwareRecord::getPrice() const
{
    return myPrice;
}

void HardwareRecord::setDescription(string description)
{
    this->myDescription=description;
}

string HardwareRecord::getDescription() const
{
    return myDescription;
}

file: main.cpp

// file: main.cpp

#include <iostream>
#include <fstream>
#include <iomanip>
#include <cstdlib>
#include <sstream>

#include "HardwareRecord.h" //HardwareRecord definition

using namespace std;

//enumeration of choices
enum Choices { WIPE_RECORDS, UPDATE, LIST, PRINT, DELETE,
               NEW, END, LAST };

const string SELECT[] =
{
    "Wipe Records", "Update Records", "List Records",
    "Print Records", "Delete Records", "Add New Record",
    "End Program"
} ;

/* NOT needed nor used now here ...

// Note: ONLY valid choice ever gets passed in here ... //
std::ostream& operator << ( std::ostream& op, Choices choice )
{
    //print the string corresponding to the value of enum type Choices
    return op << SELECT[choice]; //print output
}

*/

//prototype of helper functions
unsigned enterChoice();
void wipeRecords( /* fstream& */ ); // can do later ... //
void updateRecord(fstream&);
void listRecords(fstream&);
void createTextFile(fstream&);
void deleteRecord(fstream&);
void newRecord(fstream&);



int main()
{
    //open file for reading and writinbg
    fstream outRecord ( "HardwareRecord.dat",
                        ios::in|ios::out|ios::binary );
    if( outRecord )
    {
        int choice; //user's choice

        do // enable user to specify action
        {
            // ONLY valid choices get returned
            choice = enterChoice(); 

            cout << "\nYour choice was " << SELECT[choice]
                 << " ... \n";

            switch( choice )
            {
                case WIPE_RECORDS: //wipe all records clean
                    wipeRecords (/*outRecord*/ );
                break;

                case UPDATE: //update a record
                    //updateRecord(outRecord);
                break;

                case LIST: //list all current records
                    //listRecords(outRecord);
                break;

                case PRINT: //print a record
                    //createTextFile(outRecord);
                break;

                case DELETE: //delete a record
                    //deleteRecord(outRecord);
                break;

                case NEW: //add a new record (if space allows)
                    //newRecord(outRecord);
                break;

                case END:
                    cout << "\nPress 'Enter' to "
                         << "continue/exit ... " << flush;
                    cin.get();
                break;
            }

            outRecord.clear();
        }
        while( choice != END );
    }
    else  //exit program if fstream cannot open file
    {
        cout  << "\nFile could not be opened." << endl;
        //exit(EXIT_FAILURE);
    }
    return 0;
}



// enable user to input choice from menu options ...
// now ... loops until there is a valid input ... //
unsigned enterChoice()
{
    unsigned menuChoice;

    // loop until have a valid input ...
    for( ; ; ) // an example of a C/C++ 'forever' loop ... //
    {
         menuChoice = LAST;

        //display avaliable options
        cout << "\nEnter your choice:\n"<< endl;
        for ( unsigned i = WIPE_RECORDS; i < LAST; ++i )
        {
            cout << i << " - " << SELECT[i] << endl;
        }
        cout << "\nEnter your choice > ";

        // 'CRASH PROOF' & make sure ONLY VALID numbers accepted //
        if( cin >> menuChoice && cin.get() == '\n' )
        {
            if( menuChoice < LAST )
                break; // break out of loop RIGHT NOw ... //
        }
        // else ... when reach here ...
        cin.clear(); // clear any cin  error flags ...
        cin.sync(); // 'flush' cin ...
        cout << "\nOnly integers in range 0.." << LAST-1
             << " are valid here.\n";
        cout << "Please try again... \n";
    }
    return menuChoice;
}


// Can do this later ... //
void wipeRecords( /* fstream& theFile*/ )
{
/*
    HardwareRecord temp; //still get the error here
    temp.setPrice(10.52);
    cout << temp.getPrice() << endl;
    for (int i = 0; i < 100; i++)
    {
        //convert record from binary and assign to temp
        //make temp "wipe itself"
    }
*/
}

I understand everything except for your usage of size_t, and the clearing of the cin error flags. What would happen with it if a person inputs a value less than 0?

I cleared it up.

Could you explain how this section of code works, (especially with the cin.clear() and cin.sync

/'CRASH PROOF' & make sure only valid numbers accepted //
        if (cin >> menuChoice && cin.get() == '\n')
        {
            if (menuChoice < LAST)
                break; //break out of loop RIGHT NOW...//
        }

        //else ... when reach here ...
        cin.clear(); //clear any cin error flags ...
        cin.sync();  //'flush' cin
        cout << "\nOnly integers in range 0..." << LAST-1 << " are valid here.\n";
        cout << "Please try again... \n";

While I appreciate your helping out with cleaning my code, you still did not offer a solution to my problem of initializing an object with no parameters (using the default values in the constructor).

This occurds when in wipeRecords, I try to do the following HardwareRecord temp;, which results in my xCode compiler saying that no matching constructor has been fount. However, when I add in parenthesies, so that the line is HardwareRecord temp();, I get the message that the "Empty parentheses interpreted as a function declaration". This means that something is wrong.

However, as NathanOliver said, this compiles on Microsoft Visual Studio without a problem. Could you offer some insight into this situation?

Did you not read, research ... and then understand the added comments?

I understand everything except for your usage of size_t, and the clearing of the cin error flags. What would happen with it if a person inputs a value less than 0?

Accepting only unsigned numbers eliminates the need to add exception code to reject negative values input ... since cin will flag as bad any neg values input and can handle by ...

if( cin >> val ) then
else ...

Once cin has error flags set ... until you clear them no more input will work ok.

Compiler error messages can sometimes be quite 'tricky' and then 'misleading'...

That is why I like to also develope in small incremental code steps ... always keeping a copy of the last 'working step' ...

This can help to locate the section of (most probably the new) code where the code error lies ...

Did you see that you were also missing a header file?

Did you try to compile the code I provided to see if all your compilers handled it ok or not?

Clean simple logic code is usually easier to debug :)

Edited 2 Years Ago by David W

What type of computer are you working on? If it's a mac, I can compress my project for you to check on your compiler.

Your code worked just fine, even when I uncommented the line HardwareRecord temp;. On mine, I get the error with No matching constructor for initialization... The text between our files seems to be the same.

Here's what I have now:

//
//  HardwareRecord.h
//  Initialize Hardware Store File
//
//  Created by Nathan Pavlovsky on 5/18/14.
//  Copyright (c) 2014 Nathan Pavlovsky. All rights reserved.
//
//  Definition of HardwareRecord class

#ifndef __Initialize_Hardware_Store_File__HardwareRecord__
#define __Initialize_Hardware_Store_File__HardwareRecord__

#include <iostream>

class HardwareRecord
{


public:

    HardwareRecord( unsigned account =0, std::string name ="",
                   std::string description ="",
                   double price =0.0 ); //constructor
    HardwareRecord operator=(const HardwareRecord&);

    //'set' and 'get' functions
    void setAccountNumber(unsigned);
    unsigned getAccountNumber() const;

    void setName(std::string);
    std::string getName() const;

    void setPrice(double);
    double getPrice() const;

    void setDescription(std::string);
    std::string getDescription() const;

    void wipeRecord(); //set everything to blank


private:
    unsigned myAccountNumber;
    std::string myName;
    std::string myDescription;
    double myPrice;
};

#endif /* defined(__Initialize_Hardware_Store_File__HardwareRecord__) */

And:

//
//  HardwareRecord.cpp
//  Initialize Hardware Store File
//
//  Created by Nathan Pavlovsky on 5/18/14.
//  Copyright (c) 2014 Nathan Pavlovsky. All rights reserved.
//
//  Implementation of HardwareRecord class definition

#include <iostream>
#include <stdexcept> //std::invalid_argument
#include "HardwareRecord.h"

using namespace std;
using std::string;
using std::invalid_argument;
HardwareRecord HardwareRecord::operator=(const HardwareRecord & aRecord)
{
    this->myAccountNumber=aRecord.myAccountNumber;
    this->myName=aRecord.myName;
    this->myDescription=aRecord.myDescription;
    this->myPrice=aRecord.myPrice;

    return *this; //allow for cascaded overloading
}

HardwareRecord::HardwareRecord(unsigned account,string name,string description,double price):myAccountNumber(account),myName(name),myDescription(description),myPrice(price)
{}


void HardwareRecord::wipeRecord()
{
    setAccountNumber(0);
    setName("");
    setPrice(0);
    setDescription("");
}

void HardwareRecord::setAccountNumber(unsigned num)
{
  myAccountNumber=num;
}

unsigned HardwareRecord::getAccountNumber() const
{
    return myAccountNumber;
}

void HardwareRecord::setName(string name)
{

    myName=name;

}

string HardwareRecord::getName() const
{
    return myName;
}

void HardwareRecord::setPrice(double price)
{
    if (price < 0)
    {
        throw invalid_argument("\nThe price can not be less than zero");
    }
    else
    {
        myPrice=price;
    }
}

double HardwareRecord::getPrice() const
{
    return myPrice;
}

void HardwareRecord::setDescription(string description)
{
    this->myDescription=description;
}

string HardwareRecord::getDescription() const
{
    return myDescription;
}

And:

//
//  main.cpp
//  HardwareStoreApplication
//
//  Created by Nathan Pavlovsky on 6/17/14.
//  Copyright (c) 2014 Nathan Pavlovsky. All rights reserved.
//
//  Application that models a store's record of inventory

#include <iostream>
#include <fstream>
#include <iomanip>
#include <cstdlib>
#include <sstream>
#include "HardwareRecord.h" //HardwareRecord definition
using namespace std;

//enumeration of choices
enum Choices {WIPE_RECORDS,UPDATE,LIST,PRINT,DELETE,NEW,END,LAST};
const string SELECT[]= {"Wipe Records","Update Records","List Records","Print Records","Delete Records","Add New Record","End Program"};

std::ostream& operator<<(std::ostream& op,const Choices& choice)
{
    //print the string corresponding to the value of enum type Choices
        op << SELECT[choice]; //print output
    return op;
}

//prototype of helper functions
unsigned enterChoice();
void wipeRecords(/*fstream&*/); //can do later
void updateRecord(fstream&);
void listRecords(fstream&);
void createTextFile(fstream&);
void deleteRecord(fstream&);
void newRecord(fstream&);

int main()
{
    //open file for reading and writinbg
    fstream outRecord ("HardwareRecord.dat",ios::in|ios::out|ios::binary);

    //exit program if fstream cannot open file
    if (outRecord)
    {



        int choice; //user's choice

        do //enable user to specify action
        {
            //ONLY valid choices get returned
            choice=enterChoice();

            cout << "\nYour choice was to " << SELECT[choice] << " ... \n";

            switch (choice)
            {
                case WIPE_RECORDS: //wipe all records clean
                    wipeRecords(/*outRecord*/);
                    break;

                case UPDATE: //update a record
                    //updateRecord(outRecord);
                    break;

                case LIST: //list all current records
                    //listRecords(outRecord);
                    break;

                case PRINT: //print a record
                    //createTextFile(outRecord);
                    break;

                case DELETE: //delete a record
                    //deleteRecord(outRecord);
                    break;

                case NEW: //add a new record (if space allows)
                    //newRecord(outRecord);
                    break;

                case END:
                    cout << "\nPress 'Enter' to continue/exit... " << flush;
                    cin.get();
                    break;
            }

            outRecord.clear();
        } while (choice != END);
    }

    else //exit program if fstream cannot open file
    {
        cerr << "\nFile could not be opened." << endl;
        exit(EXIT_FAILURE);
    }
    return 0;
}

//enable user to input menu choice from menu options
//now ... loops until there is a valid input. //
unsigned enterChoice()
{
    unsigned menuChoice;

    //loop until have a vailid input
    for (;;) //example of a C/C++ 'forever' loop ... //
    {
        menuChoice = LAST;

        //display avaliable options
        cout << "\nEnter your choice: \n" << endl;
        for (unsigned i=WIPE_RECORDS; i < LAST; i++)
        {
            cout << i << " - " << SELECT[i] << endl;
        }

        cout << "\nEnter your choice > ";

        //'CRASH PROOF' & make sure only valid numbers accepted //
        if (cin >> menuChoice && cin.get() == '\n')
        {
            if (menuChoice < LAST)
                break; //break out of loop RIGHT NOW...//
        }

        //else ... when reach here ...
        cin.clear(); //clear any cin error flags ...
        cin.sync();  //'flush' cin
        cout << "\nOnly integers in range 0..." << LAST-1 << " are valid here.\n";
        cout << "Please try again... \n";
    }
    return menuChoice;
}

//Can do this later ... //
void wipeRecords(/*fstream& theFile*/)
{
   HardwareRecord temp;/*
    for (int i=0; i < 100;i++)
    {
        //convert record from binary and assign to temp
        //make temp "wipe itself"
    }
 */
}

What's wrong now?

you still did not offer a solution to my problem of initializing an object with no parameters (using the default values in the constructor).

Please note the changes to your erroroneous (ctor) code that were made here ...

HardwareRecord::HardwareRecord( int account, string name, string description, double price )
: myAccountNumber(account), myName(name), myDescription(description), myPrice(price)
{
    /* *** NO ***
    setAccountNumber(account);
    setName(name);
    setPrice(price);
    setDescription(description);
    */
}

What type of computer are you working on? If it's a mac, I can compress my project for you to check on your compiler.

I use Window 7 OS on ACER Laptop with Intel i5 CPU (64-bit OS)

Your code worked just fine, even when I uncommented the line

HardwareRecord temp;

When I just now made these code changes ...
all compiled and output was as expected ... ok.

// Can do this later ... //
void wipeRecords( /* fstream& theFile*/ )
{

    HardwareRecord temp; 
    cout << "\nInside wipeRecords default ctor called ok ... \n"; // prints ok when choice 0 called //
    /*
    temp.setPrice(10.52);
    cout << temp.getPrice() << endl;
    for (int i = 0; i < 100; i++)
    {
        //convert record from binary and assign to temp
        //make temp "wipe itself"
    }
*/

On mine, I get the error with No matching constructor
for initialization...

I thought you said (the code I sent) worked ok on (both) your compiler(s) ?

I don't see the reason why your code works and mine does not. My program also does the initiation like this:

HardwareRecord::HardwareRecord( int account, string name, string description, double price )
: myAccountNumber(account), myName(name), myDescription(description), myPrice(price)

Ok ... here is a 'debugging' problem / solution process to try :)

Take my code ...
compile
check

Then replace blocks/functions with 'comparable code'
from your program ...
compile and check ...
to find the code problem

Edited 2 Years Ago by David W

You need to add ...

#include <cstdlib> // re. exit

but do not use exit ...

It's not really needed ...
Just return some none 0 error (flag) value, if you wish.

(The code already prints an error message if there was a file finding/opening problem.)

You do not need to code for the overloaded =
The default supplied here is just fine.

You do not need the code for:

/*
std::ostream& operator<<(std::ostream& op,const Choices& choice)
{
    //print the string corresponding to the value of enum type Choices
        op << SELECT[choice]; //print output
    return op;
}
*/

it is not used ... since the SELECT[i] string is NOW printed

When I compiled you code on my PC it compiled ok and seemed to run op ... (quick test only)

Edited 2 Years Ago by David W

So when I have the line HardwareRecord temp; my xCode compiler raises an error. However, when I do HardwareRecord temp();, the code compiles, but I get the message that empty parentheses interpreted as a function, and it suggests replacing the parenthesies with curly brackets, which just raises another error.

It is my belief that there is something wrong with apple's compiler, as my code works on yours fine.

Well? What do you think?

I really can not tell without seeing your exact code and having the exact same testing setup.

But ... C++ code that is well written ... to accord to standard C++ ... will (normally) compile ok and run ok on any other C++ standard complient system.

Edited 2 Years Ago by David W

I could send you a .zip file with my project inside. What do you do in the real software world (like in a business setting) when there is a problem with the compiler. Do you report it to the compiler's creators? If so, how would one report the problem to Apple?

This question has already been answered. Start a new discussion instead.