How do I add exception-handling to this code and make sure it compiles and runs properly?

Discussion in 'C++' started by robinsand@gmail.com, Jun 20, 2006.

  1. Guest

    Header File: car.h #if !defined CAR_H
    #define CAR_H

    enum TCarType { ctEconomy = 1, ctCompact, ctStandard, ctFullSize,
    ctMiniVan, ctSUV };

    class Car
    {
    public:
    Car();
    Car(char *MM, int Y, int Cat);
    virtual ~Car();
    void setMakeModel(const char *mm);
    char* getMakeModel() const;
    void setCarYear(const int y);
    int getCarYear() const;
    void setCategory(const int c);
    int getCategory() const;

    private:
    char* MakeModel;
    int CarYear;
    int Category;
    };

    #endif // CAR_H



    Source File: car.cpp // Car.cpp: implementation of the Car class.

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

    #include "Car.h"

    //--------------------------------------------------------------------
    Car::Car()
    {
    setMakeModel("No Car Selected");
    setCarYear(2000);
    setCategory(1);
    }
    //--------------------------------------------------------------------
    Car::Car(char *MM, int Y, int Cat)
    {
    setMakeModel(MM);
    setCarYear(Y);
    setCategory(Cat);
    }
    //--------------------------------------------------------------------
    Car::~Car()
    {
    // delete [] MakeModel;
    }
    //--------------------------------------------------------------------
    void Car::setMakeModel(const char *m)
    {
    MakeModel = new char[strlen(m) + 1];
    strcpy(MakeModel, m);
    }
    //--------------------------------------------------------------------
    char* Car::getMakeModel() const
    {
    return MakeModel;
    }
    //--------------------------------------------------------------------
    void Car::setCarYear(const int y)
    {
    CarYear = y;
    }
    //--------------------------------------------------------------------
    int Car::getCarYear() const
    {
    return CarYear;
    }
    //--------------------------------------------------------------------
    void Car::setCategory(const int c)
    {
    Category = c;
    }
    //--------------------------------------------------------------------
    int Car::getCategory() const
    {
    return Category;
    }
    //--------------------------------------------------------------------



    Header File: customer.h #if !defined CUSTOMER_H
    #define CUSTOMER_H

    class Customer
    {
    private:
    char* FirstName;
    char* LastName;
    char* Address;
    char* City;
    char* State;
    long ZIPCode;

    public:
    void setFirstName(const char *FN);
    char* getFirstName() const { return FirstName; }
    void setLastName(const char *LN);
    char* getLastName() const { return LastName; }
    char* FullName() const;
    void setAddress(const char *Adr);
    char* getAddress() const { return Address; }
    void setCity(const char *CT);
    char* getCity() const { return City; }
    void setState(const char *St);
    char* getState() const { return State; }
    void setZIPCode(const long ZIP);
    long getZIPCode() const { return ZIPCode; }
    Customer();
    Customer(char *FName, char *LName, char *Adr,
    char *Ct, char *St, long ZIP);
    Customer(const Customer &Pers);
    Customer(char * FName, char * LName);
    ~Customer();
    };

    #endif // CUSTOMER_H



    Source File: customer.cpp
    //---------------------------------------------------------------------------
    #include <iostream>
    using namespace std;
    #pragma hdrstop

    #include "Customer.h"

    //---------------------------------------------------------------------------
    char *Customer::FullName() const
    {
    char *FName = new char[40];
    strcpy(FName, FirstName);
    strcat(FName, " ");
    strcat(FName, LastName);

    return FName;
    }
    //---------------------------------------------------------------------------
    Customer::Customer()
    : ZIPCode(0)
    {
    FirstName = new char[20];
    strcpy(FirstName, "John");
    LastName = new char[20];
    strcpy(LastName, "Doe");
    Address = new char[40];
    strcpy(Address, "123 Main Street Apt A");
    City = new char[32];
    strcpy(City, "Great City");
    State = new char[30];
    strcpy(State, "Our State");
    }
    //---------------------------------------------------------------------------
    Customer::Customer(char * FName, char * LName)
    : ZIPCode(0)
    {
    FirstName = new char[strlen(FName) + 1];
    strcpy(FirstName, FName);
    LastName = new char[strlen(LName) + 1];
    strcpy(LastName, LName);
    Address = new char[40];
    strcpy(Address, "123 Main Street Apt A");
    City = new char[32];
    strcpy(City, "Great City");
    State = new char[30];
    strcpy(State, "Our State");
    }
    //---------------------------------------------------------------------------
    Customer::Customer(char *FName, char *LName, char *Adr,
    char *Ct, char *St, long ZIP)
    : ZIPCode(ZIP)
    {
    FirstName = new char[strlen(FName) + 1];
    strcpy(FirstName, FName);
    LastName = new char[strlen(LName) + 1];
    strcpy(LastName, LName);
    Address = new char[40];
    strcpy(Address, Adr);
    City = new char[32];
    strcpy(City, Ct);
    State = new char[30];
    strcpy(State, St);
    }
    //---------------------------------------------------------------------------
    Customer::Customer(const Customer &Pers)
    : ZIPCode(Pers.ZIPCode)
    {
    FirstName = new char[strlen(Pers.FirstName) + 1];
    strcpy(FirstName, Pers.FirstName);
    LastName = new char[strlen(Pers.LastName) + 1];
    strcpy(LastName, Pers.LastName);
    Address = new char[strlen(Pers.Address) + 1];
    strcpy(Address, Pers.Address);
    City = new char[strlen(Pers.City) + 1];
    strcpy(City, Pers.City);
    State = new char[strlen(Pers.State) + 1];
    strcpy(State, Pers.State);
    }
    //---------------------------------------------------------------------------
    void Customer::setFirstName(const char *FN)
    {
    strcpy(FirstName, FN);
    }
    //---------------------------------------------------------------------------
    void Customer::setLastName(const char *LN)
    {
    strcpy(LastName, LN);
    }
    //---------------------------------------------------------------------------
    void Customer::setAddress(const char *Adr)
    {
    strcpy(Address, Adr);
    }
    //---------------------------------------------------------------------------
    void Customer::setCity(const char *CT)
    {
    strcpy(City, CT);
    }
    //---------------------------------------------------------------------------
    void Customer::setState(const char *St)
    {
    strcpy(State, St);
    }
    //---------------------------------------------------------------------------
    void Customer::setZIPCode(const long ZIP)
    {
    ZIPCode = ZIP;
    }
    //---------------------------------------------------------------------------
    Customer::~Customer()
    {
    delete [] FirstName;
    delete [] LastName;
    delete [] Address;
    delete [] City;
    delete [] State;
    }
    //---------------------------------------------------------------------------



    Header File: Invoice.h

    #if !defined INVOICE_H
    #define INVOICE_H

    #include "Customer.h"
    #include "Car.h"
    #include "RentDate.h"

    class Invoice
    {
    public:
    Invoice();
    virtual ~Invoice();
    Customer CustomerRegistration();
    void CustomerInformation(const Customer& Pers);
    Car CarSelection();
    void CarSelected(const Car& Vehicle);
    double CalculatePrice(const Car& Vehicle, double& Rate, int &Days);
    void setMileage(const long g);
    long getMileage() const;
    void setTankLevel(const char *v);
    char* getTankLevel() const;
    void setCarCondition(const char *c);
    char* getCarCondition() const;

    void ProcessOrder();
    void CarExamination();
    void ShowOrder();

    private:
    long Mileage;
    char *TankLevel;
    char *CarCondition;
    };

    #endif // INVOICE_H


    Source File: Invoice.cpp

    // Invoice.cpp: implementation of the Invoice class.
    //
    //////////////////////////////////////////////////////////////////////
    #include <iostream>
    #include <iomanip>
    #include <string>
    using namespace std;

    #include "Invoice.h"

    //////////////////////////////////////////////////////////////////////
    // Construction/Destruction
    //////////////////////////////////////////////////////////////////////

    Invoice::Invoice()
    {
    setTankLevel("Empty");
    setCarCondition("Good");
    }
    //--------------------------------------------------------------------
    Invoice::~Invoice()
    {
    }
    //--------------------------------------------------------------------
    Customer Invoice::CustomerRegistration()
    {
    char FName[20], LName[20], Addr[40], CT[32], St[30];
    long ZC = 0;

    cout << "Enter Customer Information\n";
    cout << "First Name: "; cin >> FName;
    cout << "Last Name: "; cin >> LName;
    cout << "Address: "; cin >> ws;
    cin.getline(Addr, 40);
    cout << "City: ";
    cin.getline(CT, 32);
    cout << "State: ";
    cin.getline(St, 30);
    cout << "Zip Code: "; cin >> ZC;

    Customer Cust(FName, LName, Addr, CT, St, ZC);
    return Cust;
    }
    //--------------------------------------------------------------------
    Car Invoice::CarSelection()
    {
    int CarType, ModelChosen;
    char strCarSelected[20];
    int CarSelectedYear = 2000;

    cout << "What type of car would you like to rent?";
    do {
    cout << "\n1 - Economy | 2 - Compact | 3 - Standard"
    << "\n4 - Full Size | 5 - Mini Van | 6 - Sports Utility";
    cout << "\nYour Choice: ";
    cin >> CarType;
    if( CarType < 1 || CarType > 6 )
    cout << "\nPlease type a number between 1 and 6";
    } while(CarType < 1 || CarType > 6);

    switch(CarType)
    {
    case ctEconomy:
    cout << "\nFor the Economy type, we have:"
    << "\n1 - Daewoo Lanos | 2 - Cheverolet Metro";
    cout << "\nWhich one would you prefer? ";
    cin >> ModelChosen;

    if(ModelChosen == 1)
    {
    strcpy(strCarSelected, "Daewoo Lanos");
    CarSelectedYear = 1999;
    }
    else
    {
    strcpy(strCarSelected, "Chevrolet Metro");
    CarSelectedYear = 1998;
    }
    break;

    case ctCompact:
    cout << "\nFor the Compact type, we have:"
    << "\n1 - Chevrolet Cavalier | 2 - Dogde Neon"
    << "\n3 - Nissan Sentra | 4 - Toyota Corolla";
    cout << "\nWhich one would you prefer? ";
    cin >> ModelChosen;

    if(ModelChosen == 1)
    {
    strcpy(strCarSelected, "Chevrolet Cavalier");
    CarSelectedYear = 1999;
    }
    else if(ModelChosen == 2)
    {
    strcpy(strCarSelected, "Dodge Neon");
    CarSelectedYear = 2001;
    }
    else if(ModelChosen == 3)
    {
    strcpy(strCarSelected, "Nissan Sentra");
    CarSelectedYear = 1998;
    }
    else
    {
    strcpy(strCarSelected, "Toyota Corrolla");
    CarSelectedYear = 2002;
    }
    break;

    case ctStandard:
    cout << "\nFor the Standard type, we have:"
    << "\n1 - Chevrolet Monte Carlo | 2 - Toyota Camri";
    cout << "\nWhich one would you prefer? ";
    cin >> ModelChosen;

    if(ModelChosen == 1)
    {
    strcpy(strCarSelected, "Chevrolet Monte Carlo");
    CarSelectedYear = 2000;
    }
    else
    {
    strcpy(strCarSelected, "Toyota Camri");
    CarSelectedYear = 1998;
    }
    break;

    case ctFullSize:
    cout << "\nFor the Full Size type, we have:"
    << "\n1 - Chrysler 300M | 2 - Buick Century | 3 - Infinity I30";
    cout << "\nWhich one would you prefer? ";
    cin >> ModelChosen;

    if(ModelChosen == 1)
    {
    strcpy(strCarSelected, "Chrysler 300M");
    CarSelectedYear = 2000;
    }
    else if(ModelChosen == 2)
    {
    strcpy(strCarSelected, "Buick Century");
    CarSelectedYear = 1999;
    }
    else
    {
    strcpy(strCarSelected, "Infinity I30");
    CarSelectedYear = 2003;
    }
    break;

    case ctMiniVan:
    cout << "\nFor the Mini-Van type, we have:"
    << "\n1 - Dodge Caravan | 2 - Dodge Caravan"
    << "\n3 - Pontiac Montana | 4 - Pontiac Montana | 5 - Chevrolet
    Astro Van";
    cout << "\nWhich one would you prefer? ";
    cin >> ModelChosen;

    if(ModelChosen == 1)
    {
    strcpy(strCarSelected, "Dodge Caravan");
    CarSelectedYear = 2001;
    }
    else if(ModelChosen == 2)
    {
    strcpy(strCarSelected, "Dodge Caravan");
    CarSelectedYear = 2003;
    }
    else if(ModelChosen == 3)
    {
    strcpy(strCarSelected, "Pontiac Montana");
    CarSelectedYear = 2003;
    }
    else
    {
    strcpy(strCarSelected, "Chevrolet Astro Van");
    CarSelectedYear = 2000;
    }
    break;

    case ctSUV:
    cout << "\nFor the Sport Utility type, we have:"
    << "\n1 - GMC Jimmy | 2 - Jeep Cherokee"
    << "\n3 - Chevrolet Blazer | 4 - Toyota Pathfinder";
    cout << "\nWhich one would you prefer? ";
    cin >> ModelChosen;

    if(ModelChosen == 1)
    {
    strcpy(strCarSelected, "GMC Jimmy");
    CarSelectedYear = 1998;
    }
    else if(ModelChosen == 2)
    {
    strcpy(strCarSelected, "Jeep Cherokee");
    CarSelectedYear = 2003;
    }
    else if(ModelChosen == 3)
    {
    strcpy(strCarSelected, "Chevrolet Blazer");
    CarSelectedYear = 2001;
    }
    else
    {
    strcpy(strCarSelected, "Toyota Pathfinder");
    CarSelectedYear = 2000;
    }
    break;
    }

    Car Selected(strCarSelected, CarSelectedYear, CarType);
    return Selected;
    }
    //--------------------------------------------------------------------
    void Invoice::setMileage(const long g)
    {
    Mileage = g;
    }
    //--------------------------------------------------------------------
    long Invoice::getMileage() const
    {
    return Mileage;
    }
    //--------------------------------------------------------------------
    void Invoice::setTankLevel(const char *v)
    {
    TankLevel = new char[strlen(v) + 1];
    strcpy(TankLevel, v);
    }
    //--------------------------------------------------------------------
    char* Invoice::getTankLevel() const
    {
    return TankLevel;
    }
    //--------------------------------------------------------------------
    void Invoice::setCarCondition(const char *c)
    {
    CarCondition = new char[strlen(c) + 1];
    strcpy(CarCondition, c);
    }
    //--------------------------------------------------------------------
    char* Invoice::getCarCondition() const
    {
    return CarCondition;
    }
    //--------------------------------------------------------------------
    void Invoice::processOrder()
    {
    int NbrOfDays;;
    double Rate, TotalPrice;
    // Enter Customer Information
    Customer Person = CustomerRegistration();
    cout << "\nProcess Car Information\n";
    Car Driving = CarSelection();

    TotalPrice = CalculatePrice(Driving, Rate, NbrOfDays);
    CarExamination();

    // This function works for both Borland C++ Builder and MSVC
    system("cls");

    cout << " - Bethesda Car Rental -";
    cout << "\n=============================";
    CustomerInformation(Person);
    cout << "\n------------------------------";
    CarSelected(Driving);
    cout << setiosflags(ios::fixed) << setprecision(2);
    cout << "\n------------------------------";
    cout << "\nCar Mileage: " << getMileage();
    cout << "\nCondition: " << getCarCondition();
    cout << "\nTank Level: " << getTankLevel();
    cout << "\n# of Days: " << NbrOfDays;
    cout << "\n------------------------------";
    cout << "\nRate: $" << Rate;
    cout << "\nTotal Price: $" << TotalPrice;
    cout << "\n==============================\n";
    }
    //--------------------------------------------------------------------
    void Invoice::CustomerInformation(const Customer& Pers)
    {
    cout << "\nEmployee Identification";
    cout << "\nFull Name: " << Pers.FullName();
    cout << "\nAddress: " << Pers.getAddress();
    cout << "\nCity: " << Pers.getCity() << ", "
    << Pers.getState() << " " << Pers.getZIPCode();
    }
    //--------------------------------------------------------------------
    void Invoice::CarSelected(const Car& Vehicle)
    {
    cout << "\nModel: " << Vehicle.getMakeModel();
    cout << "\nYear: " << Vehicle.getCarYear();
    }

    //--------------------------------------------------------------------
    double Invoice::CalculatePrice(const Car& Vehicle, double& DayRate,
    int &NumberOfDays)
    {
    // char WeekEndResponse;// Does the customer rent the car for the
    week-end?
    double OneDayRate, // If renting for less than 5 days including
    week-end
    WeekDay, // If renting for at least 5 days, regardless of the days
    WeekEnd = 0;// If renting for more than two days from Friday to
    monday
    //double DayRate; // Rate applied based on the number of days
    double TotalRate;

    switch(Vehicle.getCategory())
    {
    case ctEconomy:
    DayRate = 24.95;
    OneDayRate = 29.95;
    WeekDay = 24.95;
    WeekEnd = 19.95;
    break;

    case ctCompact:
    DayRate = 34.95;
    OneDayRate = 39.95;
    WeekDay = 34.95;
    WeekEnd = 25.95;
    break;

    case ctStandard:
    DayRate = 38.95;
    OneDayRate = 49.95;
    WeekDay = 38.95;
    WeekEnd = 32.95;
    break;

    case ctFullSize:
    DayRate = 44.95;
    OneDayRate = 69.95;
    WeekDay = 44.95;
    WeekEnd = 35.95;
    break;

    case ctMiniVan:
    DayRate = 54.95;
    OneDayRate = 89.95;
    WeekDay = 54.95;
    WeekEnd = 42.95;
    break;

    case ctSUV:
    DayRate = 64.95;
    OneDayRate = 89.95;
    WeekDay = 64.95;
    WeekEnd = 50.95;
    break;
    }

    cout << "\nHow many days? "; cin >> NumberOfDays;
    TotalRate = DayRate * NumberOfDays;
    return TotalRate;
    }
    //--------------------------------------------------------------------
    void Invoice::CarExamination()
    {
    char Cond;
    int GasLevel;

    cout << "Rate the car's condition (e=Excellent/g=Good/d=Driveable): ";
    cin >> Cond;
    if( Cond == 'e' || Cond == 'E' )
    strcpy(CarCondition, "Excellent");
    else if( Cond == 'g' || Cond == 'G' )
    strcpy(CarCondition, "Good");
    else if( Cond == 'd' || Cond == 'D' )
    strcpy(CarCondition, "Driveable");
    else
    strcpy(CarCondition, "Can't Decide");

    cout << "Enter the car mileage: ";
    cin >> Mileage;

    do {
    cout << "Gas level in the tank"
    << "\n1 - Considered Empty"
    << "\n2 - 1/4 Full"
    << "\n3 - Half Full"
    << "\n4 - 3/4 Full"
    << "\n5 - Full Tank";
    cout << "\nEnter the gas level: ";
    cin >> GasLevel;
    }while(GasLevel < 1 || GasLevel > 5);

    switch(GasLevel)
    {
    case 1:
    setTankLevel("Empty");
    break;
    case 2:
    setTankLevel("1/4 Full");
    break;
    case 3:
    setTankLevel("Half Full");
    break;
    case 4:
    setTankLevel("3/4 Full");
    break;
    case 5:
    setTankLevel("Full Tank");
    break;
    }
    }
    //--------------------------------------------------------------------


    Main File: Main.cpp

    #include "Invoice.h"

    void main()
    {
    CInvoice Order;

    Order.ProcessOrder();
    Order.ShowOrder();
    }
    , Jun 20, 2006
    #1
    1. Advertising

  2. Re: How do I add exception-handling to this code and make sure itcompiles and runs properly?

    * :
    > Header File: car.h #if !defined CAR_H
    > #define CAR_H
    >
    > enum TCarType { ctEconomy = 1, ctCompact, ctStandard, ctFullSize,
    > ctMiniVan, ctSUV };
    >
    > class Car
    > {
    > public:
    > Car();
    > Car(char *MM, int Y, int Cat);
    > virtual ~Car();
    > void setMakeModel(const char *mm);
    > char* getMakeModel() const;
    > void setCarYear(const int y);
    > int getCarYear() const;
    > void setCategory(const int c);
    > int getCategory() const;
    >
    > private:
    > char* MakeModel;
    > int CarYear;
    > int Category;
    > };


    Except for the constructors this is just data, make it

    struct Car
    {
    Car( std::string const& aModel, int aYear, TCarType aCategory )
    : model( aModel ), year( aYear ), category( aCategory )
    {}

    std::string model;
    int year;
    TCarType category;
    };

    Of course it is a good idea to encapsulate, to not have public data.

    But your present design is public data (expressed in an impractical
    way); if that's not your intention, get rid of all the setters.

    By the way, I saw a delete[] further down in the code.

    That's a bug, because what you're deleting is a literal string.

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
    Alf P. Steinbach, Jun 20, 2006
    #2
    1. Advertising

  3. Re: How do I add exception-handling to this code and make sure itcompiles and runs properly?

    * Alf P. Steinbach:
    > * :
    >> Header File: car.h #if !defined CAR_H
    >> #define CAR_H
    >>
    >> enum TCarType { ctEconomy = 1, ctCompact, ctStandard, ctFullSize,
    >> ctMiniVan, ctSUV };
    >>
    >> class Car
    >> {
    >> public:
    >> Car();
    >> Car(char *MM, int Y, int Cat);
    >> virtual ~Car();
    >> void setMakeModel(const char *mm);
    >> char* getMakeModel() const;
    >> void setCarYear(const int y);
    >> int getCarYear() const;
    >> void setCategory(const int c);
    >> int getCategory() const;
    >>
    >> private:
    >> char* MakeModel;
    >> int CarYear;
    >> int Category;
    >> };

    >
    > Except for the constructors this is just data, make it
    >
    > struct Car
    > {
    > Car( std::string const& aModel, int aYear, TCarType aCategory )
    > : model( aModel ), year( aYear ), category( aCategory )
    > {}
    >
    > std::string model;
    > int year;
    > TCarType category;
    > };
    >
    > Of course it is a good idea to encapsulate, to not have public data.
    >
    > But your present design is public data (expressed in an impractical
    > way); if that's not your intention, get rid of all the setters.
    >
    > By the way, I saw a delete[] further down in the code.
    >
    > That's a bug, because what you're deleting is a literal string.


    Sorry, it's a bug, but I forgot what the bug was between the time of
    reading the code and writing the reply. So the "because..." above is
    wrong. Try to figure out what the bug is.

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
    Alf P. Steinbach, Jun 20, 2006
    #3
  4. Phlip Guest

    > How do I add exception-handling to this code and make sure it compiles
    > and runs properly?


    That would be the subject of many books - most of them titled something like
    /Exceptional C++/ by Herb Sutter.

    Ordinarily, I would tell you to write unit tests for every step of your
    code. However, a unit test cannot fail reliably if code is not
    exception-safe, even if the test arranges for the code to throw exceptions,
    then catches them. So the following is a spot-check.

    robinsand wrote:

    > Header File: car.h #if !defined CAR_H
    > #define CAR_H
    >
    > enum TCarType { ctEconomy = 1, ctCompact, ctStandard, ctFullSize,
    > ctMiniVan, ctSUV };
    >
    > class Car
    > {
    > public:
    > Car();
    > Car(char *MM, int Y, int Cat);
    > virtual ~Car();
    > void setMakeModel(const char *mm);
    > char* getMakeModel() const;


    Why a char *? Why not a std::string?

    And why does the get() return a non-constant pointer? In theory, its
    implementation should not compile, but that's not going to help exception
    safety.

    > Car::Car()


    Right here, you ought to construct every variable. That means your pointers
    should get NULL. (And they should then become std::string, which won't need
    a constructor here.)

    Proper construction is very important for exception safety because if
    anything could throw then nothing should leak.

    > {
    > setMakeModel("No Car Selected");
    > setCarYear(2000);
    > setCategory(1);


    That 1 should be ctEconomy.

    > }


    > //--------------------------------------------------------------------
    > Car::Car(char *MM, int Y, int Cat)
    > {
    > setMakeModel(MM);
    > setCarYear(Y);
    > setCategory(Cat);
    > }


    You have two constructors doing nearly the same thing. That's okay in some
    situations, but here you could just merge them like this:

    Car::Car(char *MM = "No Car Selected", int Y = 2000, int Cat = ctEconomy)

    > void Car::setMakeModel(const char *m)
    > {
    > MakeModel = new char[strlen(m) + 1];
    > strcpy(MakeModel, m);
    > }


    Right - MakeModel should be a std::string, so it would take care of the
    buffer manipulations for you.

    The remaining objections are nearly the same. Using more Standard Library
    objects should reduce the odds of a leak if a stray exception throws.

    In general you must make sure that all your objects destroy safely, and they
    already do if they call 'delete'. The goal is to make your code safer for
    programmers to edit and upgrade without risking its exception safety.

    --
    Phlip
    http://c2.com/cgi/wiki?ZeekLand <-- NOT a blog!!!
    Phlip, Jun 20, 2006
    #4
  5. Peter Guest

    wrote:
    > Header File: car.h #if !defined CAR_H
    > #define CAR_H
    >
    > enum TCarType { ctEconomy = 1, ctCompact, ctStandard, ctFullSize,
    > ctMiniVan, ctSUV };
    >


    this enumeration should be part of the car class to avoid that it is
    polluting the global name space.


    > class Car
    > {
    > public:
    > Car();


    I doubt that you want an uninitialized car. There is no notion of
    uninitialized cars in the real world thus there is also no need to have
    such a car in your application.
    If you need to use arrays of cars use arrays of pointers to cars.


    > Car(char *MM, int Y, int Cat);


    I doubt that you want to pass a pointer to a writeable string here.
    I guess it should be const char *MM.


    > virtual ~Car();
    > void setMakeModel(const char *mm);
    > char* getMakeModel() const;


    I doubt that you want to return a pointer to a writeable string here.
    I guess it should be


    const char* getMakeModel() const;

    or even better and more secure

    std::string getMakeModel() const;


    > void setCarYear(const int y);
    > int getCarYear() const;
    > void setCategory(const int c);
    > int getCategory() const;
    >
    > private:
    > char* MakeModel;


    Why do you want to allocate string buffers by yourself?
    Use std::string.
    It is much less code and much more secure.


    > int CarYear;
    > int Category;
    > };
    >
    > #endif // CAR_H
    >
    >
    >
    > Source File: car.cpp // Car.cpp: implementation of the Car class.
    >
    > #include <iostream>
    > #include <string>
    > using namespace std;
    >
    > #include "Car.h"
    >
    > //--------------------------------------------------------------------
    > Car::Car()
    > {
    > setMakeModel("No Car Selected");
    > setCarYear(2000);
    > setCategory(1);
    > }
    > //--------------------------------------------------------------------
    > Car::Car(char *MM, int Y, int Cat)
    > {
    > setMakeModel(MM);
    > setCarYear(Y);
    > setCategory(Cat);
    > }
    > //--------------------------------------------------------------------
    > Car::~Car()
    > {
    > // delete [] MakeModel;
    > }
    > //--------------------------------------------------------------------
    > void Car::setMakeModel(const char *m)
    > {
    > MakeModel = new char[strlen(m) + 1];
    > strcpy(MakeModel, m);
    > }
    > //--------------------------------------------------------------------
    > char* Car::getMakeModel() const
    > {
    > return MakeModel;
    > }
    > //--------------------------------------------------------------------
    > void Car::setCarYear(const int y)
    > {
    > CarYear = y;
    > }
    > //--------------------------------------------------------------------
    > int Car::getCarYear() const
    > {
    > return CarYear;
    > }
    > //--------------------------------------------------------------------
    > void Car::setCategory(const int c)
    > {
    > Category = c;
    > }
    > //--------------------------------------------------------------------
    > int Car::getCategory() const
    > {
    > return Category;
    > }
    > //--------------------------------------------------------------------
    >
    >
    >
    > Header File: customer.h #if !defined CUSTOMER_H
    > #define CUSTOMER_H
    >
    > class Customer
    > {
    > private:
    > char* FirstName;
    > char* LastName;
    > char* Address;
    > char* City;
    > char* State;



    use std::string instead of char * here.
    e.g.
    std::string FirstName;



    > long ZIPCode;
    >
    > public:
    > void setFirstName(const char *FN);


    a person usually does not have such a method -- thus you also don't
    need it inside an application.
    You can create persons with the correct name in a single step.
    If the name is wrong, delete the person.


    > char* getFirstName() const { return FirstName; }



    you want to return const char * here.


    > void setLastName(const char *LN);
    > char* getLastName() const { return LastName; }


    same here

    > char* FullName() const;


    same here

    > void setAddress(const char *Adr);
    > char* getAddress() const { return Address; }


    same here

    > void setCity(const char *CT);
    > char* getCity() const { return City; }


    same here

    > void setState(const char *St);
    > char* getState() const { return State; }


    same here

    > void setZIPCode(const long ZIP);
    > long getZIPCode() const { return ZIPCode; }
    > Customer();


    there is no need for an uninitialized customers.
    You won't have such customers in the real world.


    > Customer(char *FName, char *LName, char *Adr,
    > char *Ct, char *St, long ZIP);



    you may want to pass a const char * for all the strings,
    since you constructor does not change these strings.


    > Customer(const Customer &Pers);
    > Customer(char * FName, char * LName);


    same here

    > ~Customer();
    > };
    >
    > #endif // CUSTOMER_H
    >
    >
    >
    > Source File: customer.cpp
    > //---------------------------------------------------------------------------
    > #include <iostream>
    > using namespace std;
    > #pragma hdrstop
    >
    > #include "Customer.h"
    >
    > //---------------------------------------------------------------------------
    > char *Customer::FullName() const
    > {
    > char *FName = new char[40];
    > strcpy(FName, FirstName);
    > strcat(FName, " ");
    > strcat(FName, LastName);
    >
    > return FName;
    > }



    you definitely want this function to return a std::string.
    Right now you have here a memory leak and also a potential buffer
    overflow.
    e.g.

    member objects:

    std::string FirstName, LastName;

    function:
    std::string Customer::FullName() const
    {
    std::string sName = FirstName + " " + LastName;

    return sName;
    }

    > //---------------------------------------------------------------------------
    > Customer::Customer()
    > : ZIPCode(0)
    > {
    > FirstName = new char[20];
    > strcpy(FirstName, "John");
    > LastName = new char[20];
    > strcpy(LastName, "Doe");
    > Address = new char[40];
    > strcpy(Address, "123 Main Street Apt A");
    > City = new char[32];
    > strcpy(City, "Great City");
    > State = new char[30];
    > strcpy(State, "Our State");



    I would try to avoid having a default customer.
    If you need array of customers make it an array of customer pointers.


    > }
    > //---------------------------------------------------------------------------
    > Customer::Customer(char * FName, char * LName)
    > : ZIPCode(0)
    > {
    > FirstName = new char[strlen(FName) + 1];
    > strcpy(FirstName, FName);
    > LastName = new char[strlen(LName) + 1];
    > strcpy(LastName, LName);
    > Address = new char[40];
    > strcpy(Address, "123 Main Street Apt A");
    > City = new char[32];
    > strcpy(City, "Great City");
    > State = new char[30];
    > strcpy(State, "Our State");
    > }
    > //---------------------------------------------------------------------------
    > Customer::Customer(char *FName, char *LName, char *Adr,
    > char *Ct, char *St, long ZIP)
    > : ZIPCode(ZIP)
    > {
    > FirstName = new char[strlen(FName) + 1];
    > strcpy(FirstName, FName);
    > LastName = new char[strlen(LName) + 1];
    > strcpy(LastName, LName);
    > Address = new char[40];
    > strcpy(Address, Adr);
    > City = new char[32];
    > strcpy(City, Ct);
    > State = new char[30];
    > strcpy(State, St);
    > }
    > //---------------------------------------------------------------------------
    > Customer::Customer(const Customer &Pers)
    > : ZIPCode(Pers.ZIPCode)
    > {
    > FirstName = new char[strlen(Pers.FirstName) + 1];
    > strcpy(FirstName, Pers.FirstName);
    > LastName = new char[strlen(Pers.LastName) + 1];
    > strcpy(LastName, Pers.LastName);
    > Address = new char[strlen(Pers.Address) + 1];
    > strcpy(Address, Pers.Address);
    > City = new char[strlen(Pers.City) + 1];
    > strcpy(City, Pers.City);
    > State = new char[strlen(Pers.State) + 1];
    > strcpy(State, Pers.State);
    > }
    > //---------------------------------------------------------------------------
    > void Customer::setFirstName(const char *FN)
    > {
    > strcpy(FirstName, FN);
    > }
    > //---------------------------------------------------------------------------
    > void Customer::setLastName(const char *LN)
    > {
    > strcpy(LastName, LN);
    > }
    > //---------------------------------------------------------------------------
    > void Customer::setAddress(const char *Adr)
    > {
    > strcpy(Address, Adr);
    > }
    > //---------------------------------------------------------------------------
    > void Customer::setCity(const char *CT)
    > {
    > strcpy(City, CT);
    > }
    > //---------------------------------------------------------------------------
    > void Customer::setState(const char *St)
    > {
    > strcpy(State, St);
    > }
    > //---------------------------------------------------------------------------
    > void Customer::setZIPCode(const long ZIP)
    > {
    > ZIPCode = ZIP;
    > }
    > //---------------------------------------------------------------------------
    > Customer::~Customer()
    > {
    > delete [] FirstName;
    > delete [] LastName;
    > delete [] Address;
    > delete [] City;
    > delete [] State;
    > }
    > //---------------------------------------------------------------------------
    >
    >
    >
    > Header File: Invoice.h
    >
    > #if !defined INVOICE_H
    > #define INVOICE_H
    >
    > #include "Customer.h"
    > #include "Car.h"
    > #include "RentDate.h"
    >
    > class Invoice
    > {
    > public:
    > Invoice();
    > virtual ~Invoice();
    > Customer CustomerRegistration();
    > void CustomerInformation(const Customer& Pers);
    > Car CarSelection();
    > void CarSelected(const Car& Vehicle);
    > double CalculatePrice(const Car& Vehicle, double& Rate, int &Days);
    > void setMileage(const long g);
    > long getMileage() const;
    > void setTankLevel(const char *v);
    > char* getTankLevel() const;
    > void setCarCondition(const char *c);
    > char* getCarCondition() const;
    >
    > void ProcessOrder();


    an invoice object does not process an order.


    > void CarExamination();


    an invoice object does does not perform a car examination.


    > void ShowOrder();



    an invoice object may be able to display itself -- pass the output
    stream as an argument.



    >
    > private:
    > long Mileage;
    > char *TankLevel;
    > char *CarCondition;


    make these two a std::string.
    >From my understanding member objects belong at the beginning of the

    class,
    since their construction comes immediately after the base class
    construction.
    So you may want to see in a single view what happens during
    construction.



    > };
    >
    > #endif // INVOICE_H
    >
    >
    > Source File: Invoice.cpp
    >
    > // Invoice.cpp: implementation of the Invoice class.
    > //
    > //////////////////////////////////////////////////////////////////////
    > #include <iostream>
    > #include <iomanip>
    > #include <string>
    > using namespace std;
    >
    > #include "Invoice.h"
    >
    > //////////////////////////////////////////////////////////////////////
    > // Construction/Destruction
    > //////////////////////////////////////////////////////////////////////
    >
    > Invoice::Invoice()
    > {
    > setTankLevel("Empty");
    > setCarCondition("Good");
    > }
    > //--------------------------------------------------------------------
    > Invoice::~Invoice()
    > {
    > }
    > //--------------------------------------------------------------------
    > Customer Invoice::CustomerRegistration()
    > {
    > char FName[20], LName[20], Addr[40], CT[32], St[30];



    Avoid fixed sized string buffers like the plague.
    Use std::string.


    > long ZC = 0;
    >
    > cout << "Enter Customer Information\n";
    > cout << "First Name: "; cin >> FName;
    > cout << "Last Name: "; cin >> LName;
    > cout << "Address: "; cin >> ws;
    > cin.getline(Addr, 40);
    > cout << "City: ";
    > cin.getline(CT, 32);
    > cout << "State: ";
    > cin.getline(St, 30);
    > cout << "Zip Code: "; cin >> ZC;
    >
    > Customer Cust(FName, LName, Addr, CT, St, ZC);
    > return Cust;
    > }
    > //--------------------------------------------------------------------
    > Car Invoice::CarSelection()
    > {
    > int CarType, ModelChosen;
    > char strCarSelected[20];


    same problem here.

    > int CarSelectedYear = 2000;
    >
    > cout << "What type of car would you like to rent?";
    > do {
    > cout << "\n1 - Economy | 2 - Compact | 3 - Standard"
    > << "\n4 - Full Size | 5 - Mini Van | 6 - Sports Utility";
    > cout << "\nYour Choice: ";
    > cin >> CarType;
    > if( CarType < 1 || CarType > 6 )
    > cout << "\nPlease type a number between 1 and 6";
    > } while(CarType < 1 || CarType > 6);
    >
    > switch(CarType)
    > {
    > case ctEconomy:
    > cout << "\nFor the Economy type, we have:"
    > << "\n1 - Daewoo Lanos | 2 - Cheverolet Metro";
    > cout << "\nWhich one would you prefer? ";
    > cin >> ModelChosen;
    >
    > if(ModelChosen == 1)
    > {
    > strcpy(strCarSelected, "Daewoo Lanos");
    > CarSelectedYear = 1999;



    I would rather go with enumerations for car types.


    > }
    > else
    > {
    > strcpy(strCarSelected, "Chevrolet Metro");
    > CarSelectedYear = 1998;
    > }
    > break;
    >
    > case ctCompact:
    > cout << "\nFor the Compact type, we have:"
    > << "\n1 - Chevrolet Cavalier | 2 - Dogde Neon"
    > << "\n3 - Nissan Sentra | 4 - Toyota Corolla";
    > cout << "\nWhich one would you prefer? ";
    > cin >> ModelChosen;
    >
    > if(ModelChosen == 1)
    > {
    > strcpy(strCarSelected, "Chevrolet Cavalier");
    > CarSelectedYear = 1999;
    > }
    > else if(ModelChosen == 2)
    > {
    > strcpy(strCarSelected, "Dodge Neon");
    > CarSelectedYear = 2001;
    > }
    > else if(ModelChosen == 3)
    > {
    > strcpy(strCarSelected, "Nissan Sentra");
    > CarSelectedYear = 1998;
    > }
    > else
    > {
    > strcpy(strCarSelected, "Toyota Corrolla");
    > CarSelectedYear = 2002;
    > }
    > break;
    >
    > case ctStandard:
    > cout << "\nFor the Standard type, we have:"
    > << "\n1 - Chevrolet Monte Carlo | 2 - Toyota Camri";
    > cout << "\nWhich one would you prefer? ";
    > cin >> ModelChosen;
    >
    > if(ModelChosen == 1)
    > {
    > strcpy(strCarSelected, "Chevrolet Monte Carlo");
    > CarSelectedYear = 2000;
    > }
    > else
    > {
    > strcpy(strCarSelected, "Toyota Camri");
    > CarSelectedYear = 1998;
    > }
    > break;
    >
    > case ctFullSize:
    > cout << "\nFor the Full Size type, we have:"
    > << "\n1 - Chrysler 300M | 2 - Buick Century | 3 - Infinity I30";
    > cout << "\nWhich one would you prefer? ";
    > cin >> ModelChosen;
    >
    > if(ModelChosen == 1)
    > {
    > strcpy(strCarSelected, "Chrysler 300M");
    > CarSelectedYear = 2000;
    > }
    > else if(ModelChosen == 2)
    > {
    > strcpy(strCarSelected, "Buick Century");
    > CarSelectedYear = 1999;
    > }
    > else
    > {
    > strcpy(strCarSelected, "Infinity I30");
    > CarSelectedYear = 2003;
    > }
    > break;
    >
    > case ctMiniVan:
    > cout << "\nFor the Mini-Van type, we have:"
    > << "\n1 - Dodge Caravan | 2 - Dodge Caravan"
    > << "\n3 - Pontiac Montana | 4 - Pontiac Montana | 5 - Chevrolet
    > Astro Van";
    > cout << "\nWhich one would you prefer? ";
    > cin >> ModelChosen;
    >
    > if(ModelChosen == 1)
    > {
    > strcpy(strCarSelected, "Dodge Caravan");
    > CarSelectedYear = 2001;
    > }
    > else if(ModelChosen == 2)
    > {
    > strcpy(strCarSelected, "Dodge Caravan");
    > CarSelectedYear = 2003;
    > }
    > else if(ModelChosen == 3)
    > {
    > strcpy(strCarSelected, "Pontiac Montana");
    > CarSelectedYear = 2003;
    > }
    > else
    > {
    > strcpy(strCarSelected, "Chevrolet Astro Van");
    > CarSelectedYear = 2000;
    > }
    > break;
    >
    > case ctSUV:
    > cout << "\nFor the Sport Utility type, we have:"
    > << "\n1 - GMC Jimmy | 2 - Jeep Cherokee"
    > << "\n3 - Chevrolet Blazer | 4 - Toyota Pathfinder";
    > cout << "\nWhich one would you prefer? ";
    > cin >> ModelChosen;
    >
    > if(ModelChosen == 1)
    > {
    > strcpy(strCarSelected, "GMC Jimmy");
    > CarSelectedYear = 1998;
    > }
    > else if(ModelChosen == 2)
    > {
    > strcpy(strCarSelected, "Jeep Cherokee");
    > CarSelectedYear = 2003;
    > }
    > else if(ModelChosen == 3)
    > {
    > strcpy(strCarSelected, "Chevrolet Blazer");
    > CarSelectedYear = 2001;
    > }
    > else
    > {
    > strcpy(strCarSelected, "Toyota Pathfinder");
    > CarSelectedYear = 2000;
    > }
    > break;
    > }
    >
    > Car Selected(strCarSelected, CarSelectedYear, CarType);
    > return Selected;
    > }
    > //--------------------------------------------------------------------
    > void Invoice::setMileage(const long g)
    > {
    > Mileage = g;
    > }
    > //--------------------------------------------------------------------
    > long Invoice::getMileage() const
    > {
    > return Mileage;
    > }
    > //--------------------------------------------------------------------
    > void Invoice::setTankLevel(const char *v)
    > {
    > TankLevel = new char[strlen(v) + 1];
    > strcpy(TankLevel, v);
    > }
    > //--------------------------------------------------------------------
    > char* Invoice::getTankLevel() const
    > {
    > return TankLevel;
    > }
    > //--------------------------------------------------------------------
    > void Invoice::setCarCondition(const char *c)
    > {
    > CarCondition = new char[strlen(c) + 1];
    > strcpy(CarCondition, c);
    > }
    > //--------------------------------------------------------------------
    > char* Invoice::getCarCondition() const
    > {
    > return CarCondition;
    > }
    > //--------------------------------------------------------------------
    > void Invoice::processOrder()
    > {
    > int NbrOfDays;;
    > double Rate, TotalPrice;
    > // Enter Customer Information
    > Customer Person = CustomerRegistration();
    > cout << "\nProcess Car Information\n";
    > Car Driving = CarSelection();
    >
    > TotalPrice = CalculatePrice(Driving, Rate, NbrOfDays);
    > CarExamination();
    >
    > // This function works for both Borland C++ Builder and MSVC
    > system("cls");
    >
    > cout << " - Bethesda Car Rental -";
    > cout << "\n=============================";
    > CustomerInformation(Person);
    > cout << "\n------------------------------";
    > CarSelected(Driving);
    > cout << setiosflags(ios::fixed) << setprecision(2);
    > cout << "\n------------------------------";
    > cout << "\nCar Mileage: " << getMileage();
    > cout << "\nCondition: " << getCarCondition();
    > cout << "\nTank Level: " << getTankLevel();
    > cout << "\n# of Days: " << NbrOfDays;
    > cout << "\n------------------------------";
    > cout << "\nRate: $" << Rate;
    > cout << "\nTotal Price: $" << TotalPrice;
    > cout << "\n==============================\n";
    > }
    > //--------------------------------------------------------------------
    > void Invoice::CustomerInformation(const Customer& Pers)
    > {
    > cout << "\nEmployee Identification";
    > cout << "\nFull Name: " << Pers.FullName();
    > cout << "\nAddress: " << Pers.getAddress();
    > cout << "\nCity: " << Pers.getCity() << ", "
    > << Pers.getState() << " " << Pers.getZIPCode();
    > }
    > //--------------------------------------------------------------------
    > void Invoice::CarSelected(const Car& Vehicle)
    > {
    > cout << "\nModel: " << Vehicle.getMakeModel();
    > cout << "\nYear: " << Vehicle.getCarYear();
    > }
    >
    > //--------------------------------------------------------------------
    > double Invoice::CalculatePrice(const Car& Vehicle, double& DayRate,
    > int &NumberOfDays)
    > {
    > // char WeekEndResponse;// Does the customer rent the car for the
    > week-end?
    > double OneDayRate, // If renting for less than 5 days including
    > week-end
    > WeekDay, // If renting for at least 5 days, regardless of the days
    > WeekEnd = 0;// If renting for more than two days from Friday to
    > monday
    > //double DayRate; // Rate applied based on the number of days
    > double TotalRate;
    >
    > switch(Vehicle.getCategory())
    > {
    > case ctEconomy:
    > DayRate = 24.95;
    > OneDayRate = 29.95;
    > WeekDay = 24.95;
    > WeekEnd = 19.95;
    > break;
    >
    > case ctCompact:
    > DayRate = 34.95;
    > OneDayRate = 39.95;
    > WeekDay = 34.95;
    > WeekEnd = 25.95;
    > break;
    >
    > case ctStandard:
    > DayRate = 38.95;
    > OneDayRate = 49.95;
    > WeekDay = 38.95;
    > WeekEnd = 32.95;
    > break;
    >
    > case ctFullSize:
    > DayRate = 44.95;
    > OneDayRate = 69.95;
    > WeekDay = 44.95;
    > WeekEnd = 35.95;
    > break;
    >
    > case ctMiniVan:
    > DayRate = 54.95;
    > OneDayRate = 89.95;
    > WeekDay = 54.95;
    > WeekEnd = 42.95;
    > break;
    >
    > case ctSUV:
    > DayRate = 64.95;
    > OneDayRate = 89.95;
    > WeekDay = 64.95;
    > WeekEnd = 50.95;
    > break;
    > }
    >
    > cout << "\nHow many days? "; cin >> NumberOfDays;
    > TotalRate = DayRate * NumberOfDays;
    > return TotalRate;
    > }
    > //--------------------------------------------------------------------
    > void Invoice::CarExamination()
    > {
    > char Cond;
    > int GasLevel;
    >
    > cout << "Rate the car's condition (e=Excellent/g=Good/d=Driveable): ";
    > cin >> Cond;
    > if( Cond == 'e' || Cond == 'E' )
    > strcpy(CarCondition, "Excellent");
    > else if( Cond == 'g' || Cond == 'G' )
    > strcpy(CarCondition, "Good");
    > else if( Cond == 'd' || Cond == 'D' )
    > strcpy(CarCondition, "Driveable");
    > else
    > strcpy(CarCondition, "Can't Decide");
    >
    > cout << "Enter the car mileage: ";
    > cin >> Mileage;
    >
    > do {
    > cout << "Gas level in the tank"
    > << "\n1 - Considered Empty"
    > << "\n2 - 1/4 Full"
    > << "\n3 - Half Full"
    > << "\n4 - 3/4 Full"
    > << "\n5 - Full Tank";
    > cout << "\nEnter the gas level: ";
    > cin >> GasLevel;
    > }while(GasLevel < 1 || GasLevel > 5);
    >
    > switch(GasLevel)
    > {
    > case 1:
    > setTankLevel("Empty");
    > break;
    > case 2:
    > setTankLevel("1/4 Full");
    > break;
    > case 3:
    > setTankLevel("Half Full");
    > break;
    > case 4:
    > setTankLevel("3/4 Full");
    > break;
    > case 5:
    > setTankLevel("Full Tank");
    > break;
    > }
    > }
    > //--------------------------------------------------------------------
    >
    >
    > Main File: Main.cpp
    >
    > #include "Invoice.h"
    >
    > void main()
    > {
    > CInvoice Order;
    >
    > Order.ProcessOrder();
    > Order.ShowOrder();
    > }



    I don't see any errors which you may want to convert into C++
    Exceptions.
    C++ Exceptions are superiour to return codes, as they may contain a lot
    more information
    and you don't need to check for return codes.
    Remember also that using C++ Exceptions you can abort the construction
    of an object.
    Peter, Jun 20, 2006
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Thomas G. Marshall
    Replies:
    5
    Views:
    785
    Thomas G. Marshall
    Aug 6, 2004
  2. Rock
    Replies:
    4
    Views:
    424
    Jim Langston
    Nov 20, 2005
  3. Replies:
    0
    Views:
    540
  4. Suresh V
    Replies:
    4
    Views:
    247
    Suresh V
    Apr 12, 2010
  5. froil
    Replies:
    4
    Views:
    109
    J├╝rgen Exner
    Mar 8, 2006
Loading...

Share This Page