Okay, so I have an assignment for a class that requires us to use a series of classes together, to simulate a police officer issuing a ticket.
Here's how it works:
ParkedCar class:
To know the cars make, model, color, license number, and the number of minutes
that the car has been parked
ParkingMeter Class:
know how much time has been purchased
ParkingTicket Class:
know make, model, color, license of the car, calculate the fine, as well as the name and badge number of the officer issuing the ticket
PoliceOfficer Class:
Know the name a badge number of the officer
AND
Examine ParkedCar and ParkingMeter objects and determine if a ticket is needed, if so, generate a ParkingTicket object.
Here's what code I have so far:
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<ctime>
using namespace std;
class ParkedCar
{
string sMake;
string sModel;
string sColor;
string sPlate;
int iMinsParked;
public:
ParkedCar();
string getMake() const
{ return sMake; }
void setMake(string temp)
{ sMake = temp; }
string getModel() const
{ return sModel; }
void setModel(string temp)
{ sModel = temp; }
string getColor() const
{ return sColor; }
void setColor(string temp)
{ sColor = temp; }
string getPlate() const
{ return sPlate; }
void setPlate(string temp)
{ sPlate = temp; }
int getMins() const
{ return iMinsParked; }
};
ParkedCar::ParkedCar()
{
srand(time(NULL));
iMinsParked = (rand() % 10000);
}
class ParkingMeter
{
int iMinsPurch;
public:
void setMins(int temp)
{ iMinsPurch = temp; }
int getMins() const
{ return iMinsPurch; }
}
class Ticket : public ParkedCar
{
public:
string getName()
{ return sName; }
int getBadge()
{ return iBadge; }
};
class Officer
{
string sName;
int iBadge;
public:
friend string Ticket::getName();
//{ return sName; }
friend int Ticket::getBadge();
//{ return iBadge; }
};
int main()
{
ParkedCar Park;
cout << endl << endl;
cout << Park.getMins();
cout << endl << endl;
return 0;
}
Where I'm confused is mostly on the Ticket and Officer classes. The assignment clearly wants Ticket to have it's own information from all the other classes, but I'm not sure how to pass that information along. I've tried making it a child class of ParkedCar, but I just get a multiple definitions error. And I can't get the friend functions to work. I've tried them both ways and if I make them within Ticket, it tells me Officer isn't defined. And I'm really confused on how I'm supposed to write code for Officer generating an instance of Ticket when nothing has actually been initialized yet.
So:
How do I get all the information into the Ticket class?
How would I get Officer to generate an instance of Ticket?
Please keep in mind this is a STUDENT assignment, not something professional. I just want to do what the assignment says. I'm not interested in ways "around" the problem, because that's not what the prof wants.
Thanks in advance for your time. :D
Firstly: learn to use constructors. All this stuff you're setting...it is integral to the identity of a car, or a cop, etc. It should have been provided when the object was built. C++ isn't Java; quit treating classes like Java beans. :P
Secondly, a Ticket is not a ParkedCar. It associates with a car, but is not one itself. Consider instead:
class Ticket {
ParkedCar violator;
Officer issuer;
public:
Ticket(const Officer &cop, const ParkedCar &car) :
violator(car), issuer(cop) {
}
ParkedCar getCar() { return violator; }
Officer getOfficer() { return issuer; }
// Note, no mutators here!
// The biggest reason you had to have mutators, is that your construction
// was incomplete.
// The info associated with a Ticket should not be modified once the ticket
// is written. And since the constructor has all the info needed, there's no
// need to provide a way to modify them.
};
So an Officer doesn't need to know about the potentially-intricate details of a car, or exactly what info a Ticket needs. He can just hand himself and the car over to the constructor, and trust that it will extract whatever info it needs. (In this case, we just store copies of both items.)
class Officer {
std::string name;
int badge_number;
public:
Officer(const std::string& name, int badge) : name(name), badge_number(badge) { }
public std::string getName() { return name; }
public int getBadgeNumber() { return badge_number; }
Ticket writeTicketFor(const ParkedCar &violator) {
return Ticket(*this, violator);
}
};
Related
I have a basic class ContactDetails which has a private variables as string name and string address. This ContactDetails data structure is used in my program for all entities. For some entities, I need other info on top of name and address, such as phone number, pin code etc. How to design the class.
class ContactDetails {
private:
std::string name;
std::string address;
public:
ContactDetails() {
this->name = "";
this->address = "";
}
std::string getName() { return name; }
std::string getAddress() { return address; }
void setName(std::string n) { name = n; }
void setAddress(std::string n) { address = n; }
}
class ContactDetailsHelper {
public:
ContactDetails getX() {
ContactDetails obj;
obj.setName("X");
obj.setAddress("New York");
return obj;
}
ContactDetails getY() {
//Y has phone number, pin code, county code etc details available.
ContactDetails obj;
obj.setName("Y");
obj.setAddress("Chicago");
//need to set more details in the object
return obj;
}
If we take phone number, pin code, county code as a private member in ContactDetails class, most of the time it would be empty. So how to design the class in such a way like extra details we could put it in another class and if needed for any entity we could use them.
I'm new in oop and don't know how to specify this problem globally. I have two classes. Client
class Client
{
private:
int code;
string name;
public:
Client(int c, string n);
int getCode();
string getName();
};
Client::Client(int c, string n)
{
this->code = c;
this->name = n;
}
int Client::getCode()
{
return this->code;
}
string Client::getName()
{
return this->name;
}
and Account
class Account
{
private:
int number;
double balance;
double interestRate;
Client* owner;
};
and I have method like this:
Client* Account::getOwner()
{
return this->something;
}
Can you please tell me, how can I get client's code and name from this method?
Can you please tell me, how can I get client's code and name from this method?
The method is called getOwner. A method called getOwner should ... get ... the owner. Nothing else.
If you want to get the owner's name, either write a new method
string getOwnerName() const { return owner->getName(); }
or ...
(better because it reduces coupling between the Account and Client classes, possibly worse because it depends on exposing the owner directly, but then you're already doing that ...)
... just delegate this to the client code:
cout << account->getOwner()->getName();
There's still a whole load of stuff I do not understand about objects and classes in c++, nothing I have read so far has helped me understand any of it and I'm slowly piecing information together from exercises I manage to complete.
Few main points:
When an object is created from a class, how can you access the name of the object in a function in another class? What type of variable is the name of the object stored in? is it even stored anywhere after it's creation?
My manual has an example of creating an association between two classes;
Aggregationclass
{
public:
...
private:
Partclass* partobject_;
...
};
What does this actually mean? Aggregationclass can access the object partobject in partclass? what variables can be read by aggregationclass from the partclass?
Here is a exercise I'm stuck on from my c++ OOP introductionary class, that expects me to utilize association between classes. (7(2/2)/11)
It consists of uneditable Car class;
#include <iostream>
#include <string>
using namespace std;
class Car
{
public:
void Move(int km);
void PrintDrivenKm();
Car(string make, int driven_km);
private:
string make_;
int driven_km_;
};
Car::Car(string make, int driven_km) : make_(make), driven_km_(driven_km)
{
}
void Car::Move(int km)
{
driven_km_ = driven_km_ + km;
cout << "Wroom..." << km << " kilometers driven." << endl;
}
void Car::PrintDrivenKm()
{
cout << make_ << " car has been driven for" << driven_km_ << " km" << endl;
}
What I have made so far(Person class); I have written most of my questions in comments of this section.
class Person //how do I associate Person class with Car class in a way that makes sense?
{
public:
void ChangeCar(string);
Person(string, string);
int DriveCar(int);
private:
Car* make_;
Car* driven_km_;
string name_;
};
Person::Person(string name, string make) //How do I ensure string make == object created from class Car with same name?
{
Person::name_ = name;
Car::make_ = make_;
}
int Person::DriveCar(int x) //Is this the correct way to use a function from another class?
{
Car::Move(x);
}
void Person::ChangeCar(string y) //this function is wrong, how do I create a function that calls for object from another class with the parameter presented in the call for this function (eg. class1 object(ferrari) = class1 object holds the values of object ferrari from class2?)?
{
Car::make_ = y;
}
and an uneditable main();
int main()
{
Car* dx = new Car("Toyota corolla DX", 25000);
Car* ferrari = new Car("Ferrari f50", 1500);
Person* driver = new Person("James", dx);
dx->PrintDrivenKm();
driver->DriveCar(1000);
dx->PrintDrivenKm();
ferrari->PrintDrivenKm();
driver->ChangeCar(ferrari);
driver->DriveCar(20000);
ferrari->PrintDrivenKm();
return 0;
}
disclaimer: the exercise has been translated from another language, in case of spotting a translation error I failed to notice, please do give notice and I will do my best to fix.
Finished exercise; thank you, u/doctorlove for taking the time with your replies, I can with confidence say that I learned a lot!
class Person
{
public:
void ChangeCar(Car * y);
Person(String name, Car * Car);
int DriveCar(int);
private:
Car * Car_;
int x;
string name_;
string y;
};
Person::Person(string name, Car * Car) : name_(name), Car_(Car)
{
Person::name_ = name;
}
int Person::DriveCar(int x)
{
Car_->Move(x);
}
void Person::ChangeCar(Car * y)
{
Car_ = y;
}
Before talking about pointers, look at the Car class:
class Car
{
public:
void Move(int km);
void PrintDrivenKm();
Car(string make, int driven_km);
private:
string make_;
int driven_km_;
};
You can't get to the private stuff from outside. Period.
You can make (or construct) one
Car car("Zoom", 42);
Since we can see what the constructor does
Car::Car(string make, int driven_km) : make_(make), driven_km_(driven_km)
{
}
it's clear it saves away the string and int in the private member variables make_ and driven_km_.
Now we can call the public functions on this instance:
car.PrintDrivenKm();
car.Move(101);
car.PrintDrivenKm();
So, we've made a car and called some functions.
We could make a car pointer and call its functions too. We need to delete stuff otherwise we leak.
Car * car = new Car("Zoom", 42);
car->PrintDrivenKm();
car->Move(101);
car->PrintDrivenKm();
delete car;
Now to your problems.
You have a started writing a Person class which has two (private) cars (pointers) make_ and driven_km_. The constructor Person(string, string); takes two strings, but main doesn't send it two strings:
Car* dx = new Car("Toyota corolla DX", 25000);
// ...
Person* driver = new Person("James", dx);
It will be sent a string and a Car *; something like this
Person(string name, Car *car);
So perhaps it only needs one car (pointer), Car *car_?
Now as for calling your car pointer, Car has Move method; an instance method not a static method, so call it on an instance:
int Person::DriveCar(int x)
{
//Car::Move(x); //no - which car do we move, not a static on ALL cars
car_->Move(x);
}
Now, if the person wants to change car, you made person take a string:
void Person::ChangeCar(string y)
{
//what goes here?
// you want a Car * from a string...
// we did that before
delete car_; //not exception safe, but ...
car_ = new Car(y);
}
Look back at mian:
driver->ChangeCar(ferrari);
so the calling code will try to send a car (pointer) to swap to. So, get the signature right:
void Person::ChangeCar(Car * y)
{
car_ = y;
}
If you owned the pointers, you would need a destructor to tidy up pointers.
Tell whoever set wrote the code in main to delete their pointers!
Edit:
To re-iterate, in any of the Person you can call the methods on the meber variable car_ functions e.g.
void Person::ChangeCar(Car * y)
{
car_ = y;
y->PrintDriveKm(); //call a method on a car pointer.
car_->PrintDriveKm();
}
This is just the same as calling methods on pointers, as mentioned near the top of my answer.
Go back to
Car* dx = new Car("Toyota corolla DX", 25000);
// ...
Person* driver = new Person("James", dx);
From here, in main, you can call
dx->PrintDrivenKm();
From inside the Person constructor,
Person(string name, Car *car) : name_(name), car_(car)
{
}
You can call methods on car (or car_) inside the braces:
Person(string name, Car *car) : name_(name), car_(car)
{
std::cout << "Hello, " << name << '\n';
car_->PrintDrivenKm();
}
Of note: Car:: means something in the class/structr/namespace/scope Car - but you want to call instance methods, so need an instance name. Use -> to all methods on pointers to instances. Use . to call methods on instances.
In this code, I have created a vector of accounts in class bank, and (by my understanding) whenever I am adding an account, the bank class will create a different account object and push it into vectors, and when account constructor will initialize, it will make a different copy of customers every time a new account will be made through account vector in bank class - Please tell me if my understanding of this thing is clear? Here I am serially assigning account number.
`
class customer
{
string customerName;
string customerAddress;
int phoneNumber;
public:
customer(string customerName, string customerAddress, int phoneNumber)
{
this->customerName=customerName;
this->customerAddress=customerAddress;
this->phoneNumber=phoneNumber;
}
};
class account
{
customer customerObject;
int accountNumber;
static int accountBalance;
public:
account(int accountNumber, int accountBalance)
{
customer customerObject(customerName, customerAddress, phoneNumber);
this->accountNumber=accountNumber;
this->accountNumber=accountNumber;
}
int getBalance()
{
return accountBalance;
}
};
int account::accountBalance=0;
class bank
{
vector<account> accountContainer;
static int accountNumber;
int accountBalance=0;
public:
void addAccount(int deposit, string customerName, string customerAddress, int phoneNumber)
{
account accountObject(++this->accountNumber, this->accountBalance+deposit, customerName, customerAddress, phoneNumber);
accountContainer.push_back(accountObject);
}
void getBalance(int accountNumber)
{
if(accountNumber<=this->accountNumber)
{
return accountContainer[accountNumber-1].getBalance;
}
}
}
};
int bank::accountNumber=0;
int bank::accountBalance=0;
`
You are mostly correct. Only a single new customer object will be created each time you create a new account.
#include <string>
#include <vector>
#include <iostream>
#include <memory>
using namespace std;
class customer
{
string m_customerName;
string m_customerAddress;
int m_phoneNumber;
public:
customer(const std::string& customerName, const string& customerAddress, int phoneNumber)
{
m_customerName=customerName;
m_customerAddress=customerAddress;
m_phoneNumber=phoneNumber;
}
};
class account
{
customer m_customerObject;
int m_accountNumber;
int m_accountBalance;
public:
account(int accountNumber, int accountBalance, const std::string& customerName, const string& customerAddress, int phoneNumber):
m_customerObject(customerName, customerAddress, phoneNumber)
{
m_accountNumber=accountNumber;
m_accountBalance=accountBalance;
}
int getBalance()
{
return m_accountBalance;
}
};
class bank
{
vector<account> accountContainer;
public:
bank()
{
}
void addAccount(int accountNumber, int accountBalance, int deposit, const string& customerName, const string& customerAddress, int phoneNumber)
{
account accountObject(accountNumber, accountBalance+=deposit, customerName, customerAddress, phoneNumber);
accountContainer.push_back(accountObject);
}
int getBalance(int accountNumber)
{
try{
int balance = accountContainer.at(accountNumber).getBalance();
}
catch(std::exception& ex)
{
std::cout<<"Exception: "<<ex.what()<<std::endl;
}
}
};
int main()
{
bank b;
b.addAccount(1, 100, 2000,"John","222 Foo Street", 2222);
b.addAccount(2, 3000, 2000,"Roger","101 Apple Lane", 1111);
std::cout<<b.getBalance(0)<< std::endl;
std::cout<<b.getBalance(1);
return 0;
}
accountContainer.push_back(accountObject);
will copy accountObject into the accountContainer vector. So you have two instances of the account class. When addAccount returns, accountContainer goes out of scope and it is destroyed but the instance in the vector still exists.
See
http://www.cplusplus.com/reference/vector/vector/push_back/
it says this for push_back
Add element at the end
Adds a new element at the end of the vector, after its current last element. The content of val is copied (or moved) to the new element.
The compiler is however allowed to do all kinds of optimization as long as the end result is correct. Therefore it can be difficult to say exactly which functions (aka constructors/destructors) will be called during execution of the function. It may depend on optimization level. But the end result will always be correct. In this case the end result is that the vector holds an instance of the accountclass.
Since your accountclass contains a customer member each instance of account will of cause have its own customer instance.
Your constructor for account seems wrong as you make a local customer variable inside the constructor. Instead you shall just initialize the member variable. It could look like:
account(int account_number, int account_balance) :
customerObject(customerName, customerAddress, phoneNumber)
{
this->accountNumber=account_number;
this->accountBalance=account_balance;
}
or even:
account(int account_number, int account_balance) :
customerObject(customerName, customerAddress, phoneNumber),
accountNumber(account_number),
accounBalance(account_balance)
{}
I have the class Furniture with:
Furniture.h:
#include <iostream>
#include <string>
using namespace std;
class Furniture {
public:
Furniture();
~Furniture();
void setname(string name);
void setprice(double price);
double getprice();
string getname();
virtual void printSpecs();
private:
string name;
double price;
protected:
static int NumberOfItems;
int Id;
};
furniture.cpp:
#include "furniture.h"
Furniture::Furniture() {
}
Furniture::~Furniture() {
}
void Furniture::setname(string name) {
this->name = name;
}
string Furniture::getname()
{
return this->name;
}
void Furniture::setprice(double price) {
this->price = price;
}
double Furniture::getprice() {
return this->price;
}
void Furniture::printSpecs() {
cout<<"Price: "<<this->price<<endl;
cout<<"Name: "<<this->name<<endl;
}
int main() {
Furniture *model = new Furniture();
model->setname("FinalDestiny");
model->setprice(149.99);
model->printSpecs();
delete model;
}
Everything works fine but I want to add multiple furniture items with the same class and just update the NumberOfItems. Is there any way to do that?
Also, is my code ok? I mean, how can I improve it? I'm quite new to OOP and I'd like to learn some good practices.
Thanks.
The idea is conceptually broken. You cannot do that; you really need different objects.
Alternatively, if you really want to have multiple identical items, you can create one item and create multiple pointers to it, and maintain a separate count for the number of active items. A shared_ptr does that for instance.
That said, your code shouldn’t use pointers at all, this is a common anti-pattern in C++ code. Furthermore, your code probably shouldn’t have setters, provide a proper constructor instead:
int main() {
Furniture model("FinalDestiny", 149.99);
model.printSpecs();
}
Much shorter, simpler, and no possiblity of leaking memory.
To keep track of the number of items, you can update the number of items in the constructor:
Furniture::Furniture() {
Id = NumberOfItems++;
}
and decrement in the destructor if you want:
Furniture::~Furniture() {
NumberOfItems--;
}
To access the item by Id, you need to have an extra manager class or use a map:
std::map<int,Furniture*> items;
which you can pass as parameter to the constructor and update it there:
Furniture::Furniture(std::map& items) {
Id = NumberOfItems++;
items[Id] = this;
}
And, outside, you can simply retrieve items with:
Furniture* f = items[3];
I would write in this way
#include <iostream>
#include <string>
using namespace std;
class Furniture {
public:
Furniture(string name = "", double price = 0)
: name(name), price(price), Id(NumberOfItems++)
{}
Furniture(const Furniture &f)
: name(f.getname()), price(f.getprice()), Id(NumberOfItems++)
{}
void setname(string name) { this->name = name; }
void setprice(double price) { this->price = price; }
double getprice() const { return price; }
string getname() const { return name; }
virtual void printSpecs() {}
private:
string name;
double price;
protected:
static int NumberOfItems;
int Id;
};
int Furniture::NumberOfItems;
int main_furniture(int, char **)
{
Furniture a("product 1", 100);
Furniture x(a), y(a), z(a);
}
I've inlined just to simplify. What's interesting to you should be the copy constructor implementation, and (OT) you forget the const on getter...
Just increment NumberOfItems in the constructor, and decrement it in the destructor.
Store the furniture instances in an array or better in a vector. You can access them with an index or iterator. The NumberOfItems field doesn't belong in the furniture class, an instance of furniture shouldn't know about how many furniture items there are in the system. Use the size () method from vector to get the furniture item count.