Understanding OOP Association and Functions (c++) - c++

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.

Related

constructor not Inheriting

I was tryiing to inherit a comstructor from base class to the a derived class which was derived from another derived class of the base class.
but it says " no deafault constructor exists for class Waiverstudents " after inheriting the base class constructor.
class Student
{
private:
string StudentName, StudentID, CGPA , UpcomingSemester , UpcomingSemesterCredits;
public:
Student (string a, string b, string c , string d, string e)
{
StudentName= a;
StudentID=b;
CGPA=c;
UpcomingSemester=d;
UpcomingSemesterCredits=e;
}
string DisplayStudent()
{
cout<<StudentName<<endl<<StudentID<<endl<< CGPA <<endl<< UpcomingSemester <<endl<< UpcomingSemesterCredits;
}
};
class ScholarshipStudents: virtual public Student
{
private:
float ScholarshipPercent = 0.3;
float tution_fee;
public:
ScholarshipStudents(string a, string b, string c , string d, string e) : Student(a,b,c,d,e)
{}
float TutionFee(int a)
{
tution_fee=(a*ScholarshipPercent);
return tution_fee;
}
string DisplayScholarshipStudent()
{
DisplayStudent();
cout<<tution_fee;
}
};
class WaiverStudents: virtual public Student
{
private:
float Waiverpercent = 0.15;
float tution_fee;
public:
WaiverStudents (string a, string b, string c , string d, string e) : Student(a,b,c,d,e)
{}
float WaiverTuitionFee(int a )
{
tution_fee =(a*Waiverpercent);
}
string DisplayWaiverStudent()
{
DisplayStudent();
cout<<tution_fee;
}
};
class SpecialStudents : public WaiverStudents , public ScholarshipStudents
{
public:
SpecialStudents(string a, string b, string c , string d, string e): Student(a,b,c,d,e)
{} //in this line it shows error. " no deafault constructor exists for class Waiverstudents "
string DisplaySpecialStudent()
{
DisplayStudent();
}
};
I tried This
SpecialStudents(string a, string b, string c , string d, string e): ScholarshipStudents(a,b,c,d,e):WaiverStudents(a,b,c,d,e)
same thing happened.
please help me. to overcome the situation. why the I cant inherit the the constructor
There are several problems in your code so I'm going to provide a quick solution to the immediate problem in your question. The problem that you are experiencing is because of the way that virtual inheritance works. In virtual inheritance the most derived type (SpecialStudents in your code) calls the constructor in the base class (Student in your code). It must also call a constructor in each of the other classes it derives from (ScholarshipStudents and WaiverStudents). Since you are only invoking the constructor of SpecialStudents the compiler will implicitly try to invoke the default constructor of all other classes it inherits from and since those constructors do not exist you receive an error.
To fix this you have two options. The first is to explicitly invoke the constructors of each of the classes SpecialStudents and the second provide a default constructor in ScholarshipStudents and WaiverStudents. The most optimal choice in this case it to provide default constructors in those classes but make them protected to prevent them from being called except during the creation of a derived type.
class Student
{
// ... Other code ...
protected:
// Default constructor that handles initialization specific to this class.
Student() = default;
};
class ScholarshipStudents
{
// ... Other code ...
protected:
// Default constructor that handles initialization specific to this class.
ScholarshipStudents() = default;
};
class WaiverStudents
{
// ... Other code ...
protected:
// Default constructor that handles initialization specific to this class.
WaiverStudents() = default;
};
And finally your most derived type only needs to explicitly call the constructor in Student
class SpecialStudents : public WaiverStudents, public ScholarshipStudents
{
public:
SpecialStudents(string a, string b, string c, string d, string e)
: Student(a, b, c, d, e)
{}
};
Please be aware that there are several other problems in your code and the use of virtual inheritance to approach this problem is an incredibly terrible idea. What happens if you add another tuition based fee adjustment? How many different class types will you need to to add to support it. what happens if several more adjustments are added? Now thing about what happens if an existing fee is added or removed from an existing student. Not only will you have to recreate the student but every other reference to that original instance of Student will need to be informed of the change - otherwise they are now working with stale student data.
A rule of thumb in object oriented development is to prefer composition and aggregation over inheritance and in your case a very compelling example of why. You have created multiple derived types to support something that would be much better served as a simple attribute of student - i.e. a list of fee adjustments that can be applied to their tuition. This way when new fees and adjustments need to be applied to the student those pieces of data can be managed in a more focused and cohesive manner.
One way to do this is to start by creating a type that represents a fee adjustment. Something that has a name along with the adjustment itself. We're also going to stop using using namespace std because it's an incredibly bad practice. Instead we'll scope in the names we need via std::.
class FeeAdjustment
{
public:
FeeAdjustment(std::string name, float adjustment)
:
name_(move(name)),
adjustment_(adjustment)
{}
const std::string& Name() const
{
return name_;
}
void Set(float newAdjustment)
{
adjustment_ = newAdjustment;
}
float Get() const
{
return adjustment_;
}
private:
const std::string name_;
float adjustment_ = 0.0f;
};
Now of course you'll need to update the Student class to manage a list of adjustments as well as the overall tuition the student needs to pay. We can do that by adding a couple of new members to Student like so.
float Tuition;
std::vector<FeeAdjustment> TuitionAdjustments;
Now that we have something to track our tuition and keep our list of adjustments in a vector, we'll also want to update the constructor so that it takes the initial tuition fee. We'll also want to update the names of the parameters the constructor takes for clarity.
Student(
std::string studentName,
std::string studentId,
std::string cgpa,
std::string upcomingSemester,
std::string upcomingSemesterCredits,
float initialTution)
:
StudentName(studentName),
StudentID(studentId),
CGPA(cgpa),
UpcomingSemester(upcomingSemester),
UpcomingSemesterCredits(upcomingSemesterCredits),
Tuition(initialTution)
{}
We'll also want to add some new functionality so that we can add a fee adjustment for the student. I'll leave modifying and removing the fees up to you as an exercise.
void AddFeeAdjustment(std::string name, float feeAdjustment)
{
TuitionAdjustments.push_back(FeeAdjustment(name, feeAdjustment));
}
And finally we'll want to update DisplayStudent so that it includes a list of fees along with the adjusted tuition. To do this we we can just iterate over the list of fees and while displaying them create a total amount to be subtracted from the students tuition.
void DisplayStudent() const
{
std::string output;
std::cout
<< StudentName << "\n"
<< StudentID << "\n"
<< CGPA << "\n"
<< UpcomingSemester << "\n"
<< UpcomingSemesterCredits << "\n"
<< "Tuition = " << Tuition << "\n";
float tuitionAdjustments = 0.0f;
for (const auto& adjustmentDetails : TuitionAdjustments)
{
const float adjustment(Tuition * adjustmentDetails.Get());
std::cout
<< "Tution adjustment for " << adjustmentDetails.Name()
<< " = " << std::to_string(Tuition * adjustmentDetails.Get()) << "\n";
tuitionAdjustments += adjustment;
}
std::cout << "Tuition (Adjusted) = " << (Tuition - tuitionAdjustments) << "\n";
}
Now to do some quick validation we'll just create an instance, add some fee adjustments, and display the student.
Student student("Captain Obvlious", "777", "5.0", "Purple", "100", 10000.0f);
student.AddFeeAdjustment("Scholarship", .3f);
student.AddFeeAdjustment("Waiver", .15f);
student.DisplayStudent();
Which gives us the following output:
777
5.0
Purple
100
Tuition = 10000
Tution adjustment for Scholarship = 3000.000000
Tution adjustment for Waiver = 1500.000000
Tuition (Adjusted) = 5500```

Problem accessing object attributes from a pointer class attribute

I have the following class:
class Customer {
private:
string name;
savingAccount *savingsAccount = nullptr;
public:
void setSavingsAccount(savingAccount savingsAccount);
savingAccount* getSavingsAccount();
And methods:
savingAccount* Customer::getSavingsAccount()
{
return this->savingsAccount;
}
void Customer::setSavingsAccount(savingAccount savingsAccount)
{
this->savingsAccount = &savingsAccount;
}
savingsAccount class is derived from account struct:
struct account {
private:
double balance;
double interestRate;
double interest;
const string accountType = "Base Account";
public:
account();
double getBalance();
double getIntRate();
double calculateInterest(int n);
void setBalance(double balance);
void setIntRate(double rate);
string getType();
};
class savingAccount : public account {
public:
double savingDepositArr[5];
const string accountType = "Saving Account";
Now the problem:
I am creating SavingsAccount and Customer objects.
savingAccount newSavingAccount;
Customer customer;
customer.setSavingsAccount(newSavingAccount);
When I try to access anything through getSavingsAccount I can't.
customer.getSavingsAccount.getBalance()
customer.getSavingsAccount().getBalance()
or
customer.getSavingsAccount.accountType
I am 100% sure I am not using the pointer the right way. I have been looking for a solution for a long time, however still nothing. If I remove the pointers and just have the object as an attribute, it works but this is not the solution I am looking for. I just want to know what I am doing wrong.
Customer::getSavingsAccount() returns a pointer to a savingAccount object. To access members of that object, you need to dereference the pointer using the * operator, and then access the members using the . operator. Or, you can use the shorter -> operator:
(*customer.getSavingsAccount()).getBalance()
customer.getSavingsAccount()->getBalance()
That being said, be aware that Customer::setSavingsAccount() takes in a savingAccount object by value, so a copy of the input object is passed in. setSavingsAccount() saves a pointer to that copy. When setSavingsAccount() exits, the copy gets destroyed, leaving the pointer dangling pointing at invalid memory. Thus, anything you try to do afterwards that involves dereferencing that pointer will cause undefined behavior.
For what you are attempting to do, make setSavingsAccount() take the savingAccount object by reference instead, eg:
class Customer {
private:
...
savingAccount *savingsAccount = nullptr;
public:
void setSavingsAccount(savingAccount &savingsAccount);
...
};
void Customer::setSavingsAccount(savingAccount &savingsAccount)
{
this->savingsAccount = &savingsAccount;
}
Just make sure the input savingAccount object outlives the Customer object, or else you will still end up with a dangling pointer.
An alternative solution would be to use std::unique_ptr or std::shared_ptr instead, eg:
#include <memory>
class Customer {
private:
...
std::unique_ptr<savingAccount> savingsAccount;
public:
void setSavingsAccount(std::unique_ptr<savingAccount> savingsAccount);
savingAccount* getSavingsAccount();
};
savingAccount* Customer::getSavingsAccount()
{
return this->savingsAccount.get();
}
void Customer::setSavingsAccount(std::unique_ptr<savingAccount> savingsAccount)
{
this->savingsAccount = std::move(savingsAccount);
}
auto newSavingAccount = std::make_unique<savingAccount>();
Customer customer;
customer.setSavingsAccount(std::move(newSavingAccount));
...
customer.getSavingsAccount()->getBalance();
customer.getSavingsAccount()->accountType;
Or:
#include <memory>
class Customer {
private:
...
std::shared_ptr<savingAccount> savingsAccount;
public:
void setSavingsAccount(std::shared_ptr<savingAccount> savingsAccount);
std::shared_ptr<savingAccount> getSavingsAccount();
};
std:shared_ptr<savingAccount> Customer::getSavingsAccount()
{
return this->savingsAccount;
}
void Customer::setSavingsAccount(std::shared_ptr<savingAccount> savingsAccount)
{
this->savingsAccount = savingsAccount;
}
auto newSavingAccount = std::make_shared<savingAccount>();
Customer customer;
customer.setSavingsAccount(newSavingAccount);
...
customer.getSavingsAccount()->getBalance();
customer.getSavingsAccount()->accountType;
getSavingsAccount() returns a pointer to a savings account. If you are working with a pointer to an object, you can't access the attributes with . (unless you dereference). You can access the attributes (without dereferencing) via the shorthand ->.
Try customer.getSavingsAccount()->getBalance()

c++ double free or corruption error at end of scope

I am a novice C++ programmer who is currently a student at my local University. I am doing this assignment and I am told to create a linked list of a class called Car, to create a "train". I have two derived classes which simply print differently.
What I want to do is create a list of train cars, and have two pointers pointing to the current Car of each type (Chair and Sleeping) so I know when the user wants to book a seat of a certain type within the train, I know exactly where to go there. When a train is full, the plan is to put a new train of that type onto the end. Ex: Sleeping Car's last seat is booked, a new Sleeping Car will be created and put at the end of the train. The current Sleeping Car pointer will now point to the new Car at the end of the list.
Below is the code I have for this program:
carTest.cc
int main()
{
int trainId = 0;
list<Car> train;
// Testing Car Default Constructor
// Testing Car Constructor
//cout << "Creating a \"Chair car\"... " << endl;
Car* currChair = nullptr, *currSleep = nullptr;
train.push_back(ChairCar(trainId++));
currChair = &train.back();
train.push_back(SleepingCar(trainId++));
currSleep = &train.back();
// Testing bookSeat
//book_seat_test(car2);
// Testing isTypeAvailable
//is_type_available_test(car2);
// Testing isBooked
//is_booked_test(car2);
// Testing mostAvailable
//most_available_test(car2);
// Testing firstAvailable
//first_available_test(car2);
// Testing getSeatNumber
///get_seat_number_test(car2);
// Testing getIndex
//get_index_test(car2);
// Testing bookFirstAvailable
//book_first_available_test(car2);
// Testing chairCar printStatus
//chairCar_print_status_test(*currChair);
// Testing sleepingCar printStatus
//sleepingCar_print_status_test(*currSleep);
currSleep = nullptr;
currChair = nullptr;
return 0;
}
car.h
class Car
{
public:
class Seat
{
public:
Seat() : row(-1), col(-1) {};
Seat(int i, int j) : row(i), col(j) {};
int getRow() const { return row; }
int getCol() const { return col; }
private:
int row;
int col;
};
public:
// Contructors
Car();
explicit Car(int, int, int);
// Deconstructor
~Car();
// Public Member Functions
bool bookSeat(int, int);
bool isTypeAvailable(int) const;
bool isBooked() const;
int mostAvailable() const;
int firstAvailable(int) const;
int getSeatNumber(int, int) const;
Seat getIndex(int) const;
int bookFirstAvailable(int);
virtual void printStatus(int) const;
protected:
int carNumber;
int rows;
int cols;
bool** plan;
int* numAvailable;
int columnSeperation;
void init();
};
car.cc
// function: Deconstructor
// Description:
// The Deconstructor simply frees the dynamically allocated memory
// of the data members plan and numAvailable if the members are not pointing
// to the nullptr.
Car::~Car()
{
if(plan != nullptr)
{
delete[] plan;
plan = nullptr;
}
if(numAvailable != nullptr)
{
delete[] numAvailable;
numAvailable = nullptr;
}
}
chairCar.h
class ChairCar : public Car
{
public:
ChairCar();
ChairCar(int);
protected:
void printStatus(int seatNumber) const;
};
#endif
chairCar.cc
#include "chairCar.h"
ChairCar::ChairCar()
: Car()
{
}
ChairCar::ChairCar(int id)
: Car(7,4,id)
{
}
void ChairCar::printStatus(int seatNumber) const
{
int maxSeatNumber = (rows-1)*cols+(cols-1);
if(seatNumber > maxSeatNumber || seatNumber < 0)
throw OutOfRangeException(seatNumber, 0, maxSeatNumber);
cout << setw(columnSeperation) << ' ' << " |";
cout << setw(columnSeperation) << "WL";
cout << setw(columnSeperation) << "ML";
cout << setw(columnSeperation) << "MR";
cout << setw(columnSeperation) << "WR";
cout << endl;
Car::printStatus(seatNumber);
}
Sleeping Car is exactly the same as Chair Car except different arguments are sent to the base constructor. When I run the code in the main function I get
Error in
`/home/w1llbedone/Programming/cpsc2620/assn/a4/carTest': double free or corruption (fasttop): 0x0000000000608010
I was trying to set the currCar pointers to nullptr before end of the scope to avoid this error. Can anyone explain to me why this happens? This is my first time posting on StackExchange, so I apologise for any lack of information. Any help would be greatly appreciated.
There are at least two major bugs in the partially-shown code. Bug #1:
list<Car> train;
// ...
train.push_back(ChairCar(trainId++));
This is a textbook case of object slicing. train is a std::list of Cars. The shown code constructs a ChairCar, and puts it into the list. This slices off the ChairCar subclass, and copies the Car superclass into the list.
Bug #2 is the primary bug here: this class violates the Rule Of Three. Car's destructor clearly deletes class members that were constructed in dynamic scope. However, the Car class does not define a copy constructor, nor the assignment operator. This pretty much rules out the chances of this class being Rule-of-three compliant.
So, these two bugs result in a lethal combination. During the initial object slicing, the temporary ChairCar object gets destroyed, but only after a copy of its Car superclass gets copy-constructed into the list's container. As part of the destruction, Car's destructor deletes its dynamically-scoped class members.
Then, eventually, the list container gets destroyed, and the sliced off Car, in the list, gets destroyed, and its destructor attempts to delete the pointers that were already deleted.
Game over.

C++: how to make getters and setters work with an empty constructor

First of all, I have only learned a little bit of Java before. It's been only a few days since I started getting friendly with C++ so please don't take this question so basic and please don't degrade my question.
I made a simple source code as follows:
#include <iostream>
using namespace std;
class Car {
public:
void setBrand(string name);
void setPrice(double price);
string getBrand();
double getPrice();
Car();
Car(string name);
Car(string name, double price);
private:
string name;
double price;
};
Car::Car() {
}
Car::Car(string name) {
name = name;
}
Car::Car(string name, double price) {
name = name;
price = price;
}
void Car::setBrand(string name) {
name = name;
}
void Car::setPrice(double price) {
price = price;
}
string Car::getBrand(void) {
return name;
}
double Car::getPrice(void) {
return price;
}
int main() {
Car car;
car.setBrand("Nissan");
car.setPrice(30000);
cout << "Brand: " << car.getBrand() << endl;
cout << "Price: " << car.getPrice() << endl;
return 0;
}
I wanted to make a code that creates an empty instance of a class called Car, set the field values later and print them out on the console.
The code did not make any errors during the compile, but the result I see was totally different from what I expected. It didn't show the brand name and the price was looking even weird, as follows.
Brand:
Price: 6.95322e-310
Somebody help me out! Thank you very much indeed in advance.
The problem you have is that you override the member names with function parameters. You can use this-> to make it explicit or name the member differently.
For example:
void Car::setBrand(string name) {
this->name = name;
}
Or:
void Car::setBrand(string new_name) {
name = new_name;
}
In your constructor and setters, you make no differentiation between the local parameter and the class member.
name = name;
Both the function parameter and the class member are called name. Currently the compiler is assigning the parameter value to itself, and not affecting the class member at all. This is because the function parameter is in a more immediate scope.
Possible solutions:
Specify this when referring to the class member: this->name = name;.
Rename the function parameter: name = _name;.
For the constructor, use initializer lists:
Car::Car(string name, double price)
: name(name)
, price(price)
{ }
There's too much wrong with your code to describe it in prose, so let me present a fixed implementation, and I leave it to you to spot the difference:
#include <string>
class Car
{
private:
static constexpr double kNoPrice = -1.0;
static constexpr const char* kNoName = "[no name]";
public:
// Main constructor: constructs a car with the given name and price.
Car(std::string name, double price)
: name_(std::move(name))
, price_(price)
{}
// Convenience constructors:
Car() : Car(kNoName, kNoPrice) {}
Car(std::string name) : Car(std::move(name), kNoPrice) {}
// Accessors:
const std::string& getBrand() const { return name_; }
void setBrand(std::string name) { name_ = std::move(name); }
double getPrice() const { return price_; }
void setPrice(double price) { price_ = price; }
private:
std::string name;
double price;
};
Some random notes, in no particular order:
Use correct names. It's std::string, not string, mate or buddy. Never ever be abusing namespace std.
Include headers for external names that you need.
Reading uninitialized values is undefined behaviour, so none of your constructors should leave fields uninitialized (like price_).
Give private members consistent names (e.g. foo_ in my example).
Accessors should be const-correct.
Convenience constructors should delegate to one single work-horse constructor.
Pick sensible defaults for initial values of defaulted fields and make them discoverable.
Use move semantics when taking ownership of dynamically managed data (strings, dynamic containers, etc.).

Making a class generate another class?

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);
}
};