0

I have a base class and a derived class. Currently, I am reading each file separately i.e. the carfile and the sportsCarFile. They are then loaded as members to be used for other purposes. I am trying to get my head around how I would read one single file and then read each line in the file correctly calling the correct load function. Below is a table of what the data would look like:

Car/SportsCar  CarName Age Colour Price 
Car            Abbort  8   Yellow 899.99
SportsCar      Aufdi   7   Brown  989.99       
Car            ATX     5   White  9823.23
Car            POL     3   Yellow 8232.33   

And here is the current code:

#include "stdafx.h"

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

class Car{
public:
    Car();
    virtual void Load(ifstream& carFile);
    virtual int LoadString(string filename);
    void display();

protected:
    string CarName;
    int Age;
    string Colour;
    double Price;
    int countCars;
    Car *ptrToCarList;
};

class SportsCar : public Car
{
public: 
    SportsCar();
    virtual void LoadSports(ifstream& carFile);
    virtual int LoadString(string filename);
    void displayLoad();
    void display();
protected:
    int engineSize;
    SportsCar *ptrToSportsCarList;
    int countCars;

};

Car::Car()
{
    CarName = "Unknown";
    countCars = 0;
}

void Car::Load(ifstream& carFile)
{
    carFile >> CarName >> Age >> Colour >> Price;
}

int Car::LoadString(string filename)
{
    ifstream inFile(filename);

    if (!inFile)
    {
        cout << "Sorry, file not found" << endl;
        return -1;
    }

    ptrToCarList = new Car[countCars];

    for (int i = 0; i < countCars; i++)
    {
        ptrToCarList[i].Load(inFile);
    }
    inFile.close();
    return 0;
}

void Car::display()
{
    cout << CarName << " " << Age << " " << Colour << " " << Price << " " ;
}

void SportsCar::displayLoad() 
{
    Car::display();
    cout<<engineSize<<endl;
}

void SportsCar::display()
{
    for (int i = 0; i < countCars; i++)
    {
        ptrToSportsCarList[i].displayLoad();
    }
}


void SportsCar::LoadSports(ifstream& carFile){
    Car::Load( carFile);
    carFile >> engineSize;
}

SportsCar::SportsCar() 
{
    CarName = "Unknown";
    countCars = 0;

}

int SportsCar::LoadString(string filename)
{
    ifstream inFile(filename);

    if (!inFile)
    {
        cout << "Sorry, file not found" << endl;
        return -1;
    }
    countCars = 2;

    ptrToSportsCarList = new SportsCar[countCars];

    for (int i = 0; i < countCars; i++)
    {
         ptrToSportsCarList[i].LoadSports(inFile);
    }
    inFile.close();
    return 0;
}

int main()
{
    SportsCar example2;
    example2.LoadString("sportsCarFile.txt");
    example2.display();
    return 0;
}
Brendan Long
  • 53,280
  • 21
  • 146
  • 188
BeginnerLK
  • 33
  • 1
  • 7

2 Answers2

1

I would create a function to read cars and then return the appropriate type (using a shared_ptr so we don't need the manage the memory):

shared_ptr<Car> loadCar(ifstream& in)
{
    string type;
    in >> type; // is this syntax right? I don't use C++ very often
    shared_ptr<Car> car;
    if (type == "SportsCar") {
        car = new SportsCar();
    } else if (type == "Car") {
        car = new Car();
    } else {
        throw [some sort of exception?];
    }
    car.load(in);
}

I think this is called a factory. The advantage is that your Car-parsing code will figure out what kind of car it is, so it's something you don't have to think about when using the API:

ifstream f(filename);
vector<shared_ptr<Car>> cars;
while (!f.eof()) {
    cars.push_back(loadCar(f));
}

Note that Car::load() and SportsCar::load() should both return a single car, not a list of them like your current Car class. I chose to use a vector since they're easy to work with. Your classes are also overly complicated.

So, I would change your classes to this:

class Car{
public:
    Car();
    virtual ~Car();
    virtual void load(ifstream& carFile);
    virtual void display();

protected:
    string name;
    int age;
    string colour;
    double price;
};

class SportsCar : public Car
{
public: 
    SportsCar();
    virtual void load(ifstream& carFile);
    virtual void display();
protected:
    int engineSize;
};

Or even better, overload operator<<(), so you can just do cout << car.

Brendan Long
  • 53,280
  • 21
  • 146
  • 188
  • Thank you, I get an error that when I return SportsCar::load(in) or return Car::load(in) in the load function. error C2352: 'SportsCar::load' : illegal call of non-static member function. @Brendan Long – BeginnerLK Apr 18 '15 at 13:54
  • @BeginnerLK Sorry, I wrote parts of this at different times and didn't entirely make them match up. I changed it a bit so the `loadCar()` function creates the `Car` object and then we just call the virtual `load` functions. – Brendan Long Apr 18 '15 at 17:47
0

you go through the file, foreach line read and create a car.

so about your design:

you will need a list/vector to store the cars e.g. a CarStore with this member (std::vector cars and the function loadAll(string csvfile).

A car doesn't have a carlist....

If it will be a "real world" example I would consider using a database and/or an OR Mapper. If just for learning, carry on...

many useful hints for you since you are trying to load a CSV file:

How can I read and parse CSV files in C++? "CSV files"

Community
  • 1
  • 1
relascope
  • 4,399
  • 4
  • 22
  • 27