How can I create multiple items with one class in C++? - c++

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.

Related

Getter Setter for class

I was working on homework that my instructor wanted me to write a class named Species with setter and getter functions. I wrote that code but I can't set or get any value when I run it. Can you help me?
class Species
{
private:
string name;
string country;
int population;
int growthrate;
public:
int year;
void setName(string NameS){
NameS=name;
}
void setCountry(string CountryS){
CountryS=country;
}
void setPopulation(int pop){
pop=population;
}
void setGrowthRate(int GrowRth){
GrowRth=growthrate;
}
void setYear(int syear){
syear=year;
}
string getName() {
return name;
}
string getCountry() {
return country;
}
int getPopulation() {
return population;
}
int getGrowthrate() {
return growthrate;
}
double e=2.71828182;
double calculatePopulation() {
int b=growthrate*year;
int a=pow(e,b);
return population*a;
}
};
First of all. Your class has fields like:
string name;
string country;
int population;
int growthrate;
And your methods are like:
void setName(string NameS){
NameS=name;
}
So you want to set NameS value to the name which makes no sense.
You should assign the field like name to be equal to nameS not the opposite.
Generally, a setter should look like this.
void setVariable(const VariableType& var){
this->var=var;
}
What you did was var=this->var.
Btw, you should make your getter-s const
You should use "this" keyword to set the value to object of the class.
this: to refer current class instance variable. The this keyword can be used to refer current class instance variable.
for example:
void setName(string name){
this.name=name;
}
void setGrowthRate(int growthrate){
this.growthrate=growthrate;
"this" is very helpful in please learn more about it.

How do I invoke copy constructor appropriately while using rvalue for an object?

Here I am trying to push an object into a vector using push_back function and rvalue of that object. Look at the addMovie() function of the Movies class below
#include "Movies.h"
void Movies::addMovie(std::string name, std::string rating, int watched)
{
movieColl.push_back(Movie{name,rating,watched}); //apparently I am having problem here
}
Rest of the required parts are here
class Movies
{
public:
void addMovie(std::string name, std::string rating, int watched);
protected:
private:
std::vector <Movie> movieColl;
};
Movie class itself... I have just showed constructors here although I have implemented the other functions
class Movie
{
public:
Movie(std::string name,std::string rating, int watched = 0);
Movie(const Movie &obj);
Movie();
void getMovieDetails();
void addToWatchTime(int num = 1);
void setMovieDetails(std::string name,std::string rating, int watched = 0);
protected:
private:
std::string name;
std::string rating;
int watched;
};
Movie::Movie(std::string name,std::string rating, int watched):name{name},rating{rating},watched{watched}
{
//ctor
}
Movie::Movie(const Movie &obj):Movie(obj.name,obj.rating,obj.watched){}
Movie::Movie():Movie("None","NA",0){}
My MAIN Function
#include<iostream>
#include"Movies.h"
using namespace std;
int main()
{
Movies collection;
collection.addMovie("GG","PG",343);
return 0;
}
Use emplace_back and std::move.
movieColl.emplace_back(std::move(Movie{name,rating,watched}));
Basically there's two approach to solve this problem
Approach 1: Use default copy constructor provided by compiler.
Approach 2: This ones a bit weird. So instead of typing
movieColl.push_back(Movie{name,rating,watched});
I typed
movieColl.push_back(Movie(name,rating,watched));
Basically I changed the curlys to normal parentheses and it worked..

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.).

Using unordered_map with dyanmically-allocated user-defined class

So I've got a class, "Room", which has the following code:
class Room
{
public:
Room(string name, string desc): name(name), desc(desc) {}
void operator=(const Room room)
{
name = room.name;
desc = room.desc;
}
string getName(); //returns this.name
string getDesc(); //returns this.desc
private:
string name; //name of the room
string desc; //description of the room
};
I've got a global variable in my main.cpp of type unordered_map, like this:
unordered_map<string, *Room> rooms; //Room's name is the key
And I want to allocate Rooms on the fly in a function and add them to my map. I attempted to do it like this:
void builder()
{
Room* room = new Room("Name", "Desc");
rooms[room->getName()] = room;
}
...But I'm getting all kinds of compiler warnings. I figured it would be something to do with iterators or hashing, or I'm not using pointers correctly (which are probably all true), but mostly it seems unordered_map doesn't like being parametrized with Room or *Room. Am I missing something?
There are some syntax errors as *Room. I have some tips
#include <string>
#include <memory>
#include <unordered_map>
using namespace std;
class Room
{
public:
Room(string name, string desc)
: name(name) // This syntax is called initializer list
, desc(desc)
{
}
void operator = (const Room room)
{
name = room.name;
desc = room.desc;
}
string getName() { return name; }
string getDesc() { return desc; }
private:
string name; //name of the room
string desc; //description of the room
};
// Without using unique_ptr you have a memory leak
// because the is not explicitly called the delete operator on pointers
unordered_map<string, std::unique_ptr<Room> > rooms;
void builder()
{
Room* room = new Room("Name", "Desc");
rooms[room->getName()].reset (room);
}

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