Interaction between objects - c++

If I have a class Music like this
class Music{
private:
string song[20];
string album[20];
string artistName[20];
string genre[20];
static int i;
int j;
int duration[20];
public:
Music(string musicName,string artist,string genre,string albumname,int duration);
void addMusic(string musicName,string artist,string genre,string albumname,int duration);
bool browseMusic(string musicName);
void getParticularSongDetail(string musicName);
void totalNumberOfSongs();
};
and a person class like this
class Person{
public:
Person(string,string,string);
string getFirstName();
string getMiddleName();
string getLastName();
int getId();
private:
//some variables
}
how can I add 20 songs to Music class that belongs to a particular person?

The answer really depends on how you wish to design your program.
The following are some possible solutions for you:
The Person could have an array of Music objects.
The Music class could have a keep track of the Peron's id it belongs to.
The Music classes may be something you won't want to repeat between users, so you might make a 3rd class which helps make the associations. (e.g. Multiple people might own the same Tool album CD/mp3, so another class could help you make the associations, or you might have an array in your Music class to keep track of multiple Persons... Normally a "list" would be a better datatype than an array, however from your code examples I stuck to arrays to keep the response simple).

Related

Cinema profit calculation and movie sorting problem using C++ classes and vectors

Given a class Movie (id, title, ranking, release date, character number, ticket price, comment etc.), enum type: ACTION, COMEDY, DRAMA, FANTASY etc. and a class Cinema (name, location). I need to write a function calculateProfit ( Movie*, day) that would calculate cinema's profit based on some particular day. Also I need to write a method of choosing a movie based on some parameters and sort the movies based on release date. I've been thinking over this problem for a few days already, but it seems like I just can't write the proper code.
Here I listed my main struggles:
How to properly handle this enum, it can't be passed to the object by a constructor I used for passing everything else?
I don't know how to link these movies to a particular day. How can I create a vector in Cinema class formed by iteratevely(or maybe there is a better way of doing this?) adding objects of the Movie class, so that it will do the trick?
How to get a list of all objects of a Movie class that have the same particular attributes?
I have an idea how to write an algorithm to sort an array of release dates. But the problem is to put these dates into an array/vector. How can I iterate through objects' attributes in C++ in order to push them into my vector?
Here is the brief template for my classes:
using namespace std;
class Movie{
public:
int ID;
string Title;
int Ranking;
string ReleaseDate;
int CharacterNumber;
int TicketPrice;
string Comment;
//SortingByDate
enum type{
ACTION, COMEDY, DRAMA, FANTASY
};
Movie(int, string, int, string, int, int, string, type);
Movie();
};
Movie::Movie(int ID, string Title,int Ranking,string ReleaseDate,int CharacterNumber, int TicketPrice,string Comment, type Type){
this->ID=ID;
this->Title=Title;
this->Ranking=Ranking;
this->ReleaseDate=ReleaseDate;
this->CharacterNumber=CharacterNumber;
this->TicketPrice=TicketPrice;
this->Comment=Comment;
//this->type=Type; //How to pass enums like this using a constructor?
}
class Cinema{
private:
int calculateProfit();
public:
//Vector with objects of Movie class
string name;
string location;
};

Private Vector in Header file: How to Get and Set values

I'm trying to declare a vector containing user objects in the header file, but I'm unsure of how to use the setter and getter functions to push values objects back to the vector or call them again.
class userbase
{
public:
userbase();
virtual ~userbase();
//FUNCTION DECLARATIONS
void record_User(user);
void setUserVector(vector<user> const &newUser) {
//userbase_V = newUser;
userbase_V.push_back(newUser);
}
vector<user> const &getUservector() const {
return userbase_V;
}
protected:
private:
vector <user> userbase_V;
};
Getters/setters are quite often misunderstood. The aim of using such functions is encapsulation which means restricting access to your data or exposing certain functions.
The reason why we don't make private members public in the first place is because there are some operations that we don't want users of our class to perform.
Consider the following class:
class userbase
{
public:
vector<user> users;
};
Let's say the goal of the userbase class is to manage a loyal, unwavering list of followers of an application. And since users is a public member, we can do whatever we want with it:
class company
{
public:
void massacre()
{
m_userbase.users.clear(); // Aaaaahhh!!!
}
private:
userbase m_userbase;
};
What? Where did all our loyal, unwavering followers go? We can't just remove our users!
The company class has access to all of std::vector's functionality on m_userbase.users. But really, from userbase's point of view, we don't want the outside to access particular functions (in this case, clear() or erase()). We want to restrict what operations can be performed (modifiers) and what attributes can retrieved (accessors). That is, we want to encapsulate the users vector.
Making userbase a private member is the first step:
class userbase
{
private:
vector<user> users;
};
Now let's add some naive "encapsulation" to see if it solves our problem. (This is where a lot of misunderstanding stems from.)
Here's our new class:
class userbase
{
public:
void setUsers(vector<user> const& newUsers) {
users = newUsers;
}
vector<user> const& getUsers() const {
return users;
}
private:
vector<user> users;
}
Can the company still clear the users vector directly? Yes.
class company
{
public:
void massacre()
{
auto users = m_userbase.getUsers();
users.clear();
m_userbase.setUsers(users); // Aaaaahhh!!!
// or simply create a new vector with no data
m_userbase.setUsers(std::vector<user>{}); // Aaaaahhh!!!
}
private:
userbase m_userbase;
};
So simply providing getters/setters doesn't solve the issue.
The common approach is to instead approach it the other way around. Instead of asking "What don't I want the outside to do?", ask "What do I want to allow the outside to do?". This way, you can figure what sort of functionality to expose. This is part of designing a good API.
Maybe our API wants to be able to: add a user, get a user's name, and count the number of users. Then we would design a class like this:
class userbase
{
public:
/// modifiers:
// Add a user to the userbase.
void addUser(User const& user);
/// accessors:
// Returns the user's name given its index.
string getUserName(size_t index) const;
// Returns the number of users belonging to this userbase.
size_t numberOfUsers() const;
private:
vector<user> m_users;
};
The takeaway is: it's up to you to decide what "the outside" can or can't do with its members. You'll need to spend more time thinking and less time writing code, but this is normal.
Further reading:
Why use getter and setters? (A good read even though it's tagged with Java.)

classes with a lot of members

I am attempting to create a D&D encounter simulator.
I have therefore created a class called "Actor" to emulate the behaviour of the players and the monsters. The problem is that while the class for the moment only have 3 member variable, as the simulation gets more accurate it will become necessary to add more member variables to best simulate the stats of the monsters and player e.g. strength, dexterity etc. (possibly more than 10 member variables)
This leads to a constructor with a lot of parameters so the question then becomes; Is there a better way to organize this data, since it can all vary with every instance of the actor class?
Right now the user is required to type in all the states by hand, though I have plans to make file reading for monsters accessible later since monster stats only vary with monster type (dragon, skeleton etc.)
Note: These stats are very important and used to calculate the outcome of every action the "Actor" class can take in the encounter.
EDIT:
A lot of people suggest using inheritance, but the fact is that (Monsters and Players) never have different stats, the monsters like the players are controlled by a player (The Game Master) This is a tabletop game and the simulator is supposed to help the game master balance encounter's ahead of a real game.
Actor.h
#ifndef actor_h_
#define actor_h_
#include "dice.h"
class Actor
{
private:
signed int hp;
signed int ac; // Armor Class
signed int dmg;
public:
Actor( signed int hp, int ac, int dmg);
~Actor();
signed int getHP( void );
signed int getAC( void );
signed int getDmg( void );
void setHP(signed int newHP);
void setAC(signed int newAC);
void setDmg(signed int newDmg);
void attack(Actor* target);
};
#endif
Actor Constructor
Actor::Actor(signed int hp, signed int ac, signed int dmg)
{
this->hp = hp;
this->ac = ac;
this->dmg = dmg;
}
Actor::~Actor(){}
This leads to a constructor with a lot of parameters so the question then becomes; Is there a better way to organize this data, since it can all vary with every instance of the actor class?
Right now the user is required to type in all the states by hand, though I have plans to make file reading for monsters accessible later since monster stats only vary with monster type (dragon, skeleton etc.)
It sounds like this question is less about how to engineer the OOP, but rather how to define all the stats for the program without it being hugely cumbersome.
Reading stats from files is a good idea. You could represent them in one or more JSON files and use Nlohmann's JSON library to read it into your program. You'll still have to write code that says how your program should use the read JSON data, and of course you need to write the JSON in the first place---no free lunch. But it could nevertheless be helpful for organizing the program.
Another thought: for actors like an army of orcs, or wherever there are multiple instances of the same kind, a useful approach could be to define an orc factory function that creates an orc actor and its stats. The factory could pseudorandomly vary speed, strength, etc. so that each orc is personalized a little different without having to manually write stats for each instance.
As you bring up the example of stats yourself, those could go in a
struct StatsBlock {
int str, dex, con, /*others*/;
};
You can then either source them from static class variables or static methods:
class Skeleton : public Actor {
...
public:
static inline const StatsBlock = { 13, 8, ... };
static StatsBlock rollStats() { ... );
};
As a bonus, this also gives you a central place to apply or remove effects that change the stats temporarily, like equipping a "Ring of +1 strength" or being hit with a spell like Polymorph.
It's a basic concept of Polymorphism in C++, and I would suggest to start from reading about it
You can have for example your base class Actor will contain the basic information that every entity in your emulator has (monster, player etc.)
Then you can create a Monster and a Player class, which derive from your Actor class. Those will have their own unique information (tooth size, breaths under water, fly etc..)
If you want to dynamically create new stats for your player as the emulation goes on, I would suggest using smart pointers to hold these members for memory optimization.
If you don't want to have a parameter for each property of the stats of the actor in the constructor of the actor you can consider having a separate stats object and pass an instance of that stats to the constructor:
struct ActorStats {
signed int hp;
signed int ac; // Armor Class
signed int dmg;
}
struct Actor {
Actor(ActorStats stats) : stats_(std::move(stats)) {}
signed int getHP( void );
signed int getAC( void );
signed int getDmg( void );
void setHP(signed int newHP);
void setAC(signed int newAC);
void setDmg(signed int newDmg);
void attack(Actor* target);
protected:
ActorStats stats_;
};
You could then have different strategies of creating an actor, like reading from a save file, or from a preset:
ActorStats read_stats_from_file() {
ActorStats stats;
// some reading logic
stats.hp = // value read from file
return stats;
}
Actor create_actor() {
ActorStats stats = read_stats_from_file();
Actor actor(stats);
return Actor;
}
That way you don't need to implement a getter/setter for each stats, and don't need to use friend for the functions that should initialize the stats. But the raw values are still protected, as soon as they are passed to the Actor.

Dynamically creating two objects and assigning one to the other [duplicate]

The goal of my program is to allow the user to enter up to 100 names for people and 100 names for cars. Then the user can "register" a car to as many people as s/he wishes using pointers. I know I need a person class and a car class and I need to use two arrays of size 100 for each. But I am completely lost on how to set anything else up. I have done a lot of researching to try and figure something out. I would be extremely appreciative if anyone could give me some basic example code for how something like this could be done.
I don't have much code:
class Person{
public:
person();
Car* in_car;
};
class Car{
public:
Car();
};
int main()
{
Car cars[101];
Person people[101];
}
You could add a vector of car pointers to the People class.
class People{
...
private:
vector<Car*> _pointer;
};

How to read track & field results from a website?

I want to read track and field results from http://athletisme-quebec.ca/calendrier-et-resultats.php for members of my track & field team (I'm in charge of compiling statistics on the members).
I've written a program that adds/removes athletes and their results, and saves all the data in .txt files that can be retrieved every time we run the program. It then manipulates the data to get certain statistics I want.
I have the following classes that I need to fill with data from the websites (I omitted the methods here, since they're irrelevant to the question):
Base class Performance
class Performance {
private:
string athlete_;
string location_;
int date_;
protected:
string event_;
};
Derived class TrackPerformance
class TrackPerformance: public Performance {
private:
PerformanceTime performanceTime_;
};
Derived class FieldPerformance
class FieldPerformance: public Performance {
private:
double performanceResult_;
};
PerformanceTime class (uses double for math calculations, and string for display purposes & for entering times like 4:12.23 easily [it gets automatically converted to double, and vice-versa])
class PerformanceTime {
private:
string performanceTimeStr_;
double performanceTimeDbl_;
};
Athlete class that holds the performances of each athlete
class Athlete {
private:
string name_;
string gender_;
map < string, vector <Performance*> > performances_; // the key is the event name
};
So, what would be the best way to do it? I tried finding an API to no avail.
They all follow a similar format, so I could open each event one by one and parse it using ifstream, but I want to know if there's a better way.
Example results: http://athletisme-quebec.ca/medias/resultsindoorchpt2016.htm