function inside objects oop - c++

I don't understand what is the point of having a function inside an object if you can even modify data outside the object for example (I'm using struct for this example):
int lamborghini_horsepower1 = 350;
struct car {
string model;
string color;
int horsepower;
void check(int horsepower) {
if (horsepower > 349) {
cout << "this car has many horsepowers";
}
}
};
car ford;
ford.check(lamborghini_horsepower1);
in this case it would run anyways.
it would make sense if the function could only operate inside data of the object because as it say they are the data of the object and why can the function access to others variables? for example what if you pass another variable in this case lamborghini_horsepower is not part of the the object ford. and still can be cecked by the ford function even if they are different veichle.
are for class different?

In structs, functions don't have too much of an impact because data can be modified from the outside. However, they still can act as a convenience feature, especially when properly written. Your function takes horsepower as an argument, which is unnecessary because horsepower is already a field in the struct. If you change your function to:
void check() {
if (horsepower > 349) {
cout << "this car has many horsepowers" << endl;
}
}
you can call it with ford.check() and it'll automatically retrieve the horsepower from the ford variable. In classes, fields can be declared as private, which means that they can't be accessed from the outside and must be modified purely with functions defined inside the class.

are for class different?
Classes are not accessible from the outside by default, so if you did
class car{
string model;
string color;
int horsepower;
void check(int horsepower) {
if(horsepower>349)
{
cout << "this car has many horsepowers";
}
}
};
Then nothing in that struct would be accessible from outside the class. But there is a way to modify the what variables and functions can be accessed from the outside with access modifiers.
The purpose of making functions and variables inaccessible outside the object is to protect them from being unintentionally called or altered
The short answer is that your example wouldn't be very efficient for objects. I would just keep the function outside the struct in that example.
The purpose of classes and structs is to put variables and functions into one package. The example you have doesn't require an object. The basis behind object design is to mimic real world objects by giving them abilities(functions) and properties (variables).
The check() function here isn't an ability we normally find in cars. Instead, a car has certain properties like color, speed, and direction. A car also has abilities like accelerate, reverse, turn left and turn right. With this we can create a car object with these properties (variables) and abilities (functions)
struct Car
{
int speed;
std::string color;
std::string direction;
Car() // As soon as the object is created, this function will be called and set speed to 0.
{
speed = 0;
}
void speedUp()
{
speed += 5;
}
void slowDown()
{
speed -= 5;
}
void stop()
{
speed = 0;
}
void reverse()
{
stop() // This will stop the car first
speed -= 2; // Move the car backwords
}
void turnLeft()
{
direction = "left";
}
void turnRight()
{
direction = "right";
}
};
So now you can create different objects of the same class\struct with different speeds, direction, and color.

Related

What is the best way to initialize a more complex class construct with many unchangeable members in c++

I'm currently designing classes that should represent a chaotic storage system.
Lets say we have slots in rows and columns with certain properties.
So the slots have different restrictions in min/max height, width, length, weight and some more that come from a parameter file.
Also the Slots have a max total weight that must be checked before a new parcel gets added to that slot. And also the max weight that a row of slots can hold is lower than the sum of the max weights of the single slots. So for example each individual slot might be able to hold 50kg but the row of 10 slots must not exceed 200kg, so it is not allowed to fill every slot by 100%. The same is true for the Columns where the maximum weight is lower than the sum of the individual weights of the single rows. The row_id and column_id are atrificial numbers for adressing the slot in the physical system with barcodes or whatever that get read for positioning.
As all this parameters do not change over the lifetime of the program, my intention was to design the classes in a way that this properties are readable by getter functions but there should not be any setter functions (maybe not even private ones) in the object o the values cannot be changed by accident.
There is one class/function that reads the config-file and generates the data structure for the rows and columns with the slots. This function should be able to read the config and create objects for every column holding a row of slots and pass all the values from the config down to the slot.
Later when the program is running I also need some way to search for the best matching slot to add the next parcel or for searching parcels and unload them in a certain sequence.
So the (simplfied) basic structure of the classes would be like this:
Class Parcel {
int width;
int height;
int length;
int weight;
}
Class Slot {
vector<Parcel> parcel;
int min_width;
int max_width;
int min_height;
int max_height;
int min_length;
int max_length;
int max_total_weight;
int act_total_weight;
int total_length;
int free_length;
}
Class Row {
vector<Slot> slot;
int row_id;
int max_total_weight;
int act_total_weight;
}
Class Column {
vector<Row> row;
int column_id;
int max_total_weight;
int act_total_weight;
}
Class Storage {
vector<Column> column;
}
So here are my thoughts about how to initialize the data structure:
First possibility would be to pass all the properties in the constructor(s) of the classes, but then the constructors has some huge parameter lists specially for the Slot class that has a lot of properties.
Second thing that came to my mind (and currently my fafourite way to go) is to use config-data-structures that hold all the parameters. This parameter-objects get filled by the config-function and passed to the constructor when initializing the class. Then it also may be useful to use the parameter class as such and not having all the parameters defined in the storage class once more.
Third way is to use private setter and public getter and make the config class friends with the data structure classes to be able to access the setter functions (but i would prefer to have no setters at all in the final storage structure classes.
Fourth way that i was thinking off, was to derive child classes from the structure classes that hold the setter functions (and also some other logic needed for creating the data structure) so the child has no own variables but only additional functions. So the child class is used to fill the properties but the base class gets added to the data structure vector.
I also want to use Factory pattern to initialize the data structure because the objects have often similar or only slightly different properties. So with the second aproach after creating one row of slots I would maybe want to change the max weight of the slots in that row. Therefore I would need to change the setting in the factory and the factory then fills the parameter data structure differently and passes it to the Slot class. Or is it better to pass the data structure to the factory directly and the factory assigns it but then i think this is not what the factory pattern is meant to be.
I don't know if this is a good aproach or which of the above is best practice.
Or am I missing something and there is a way more convenient solution or this?
Thank you (and sorry if the question is maybe not the way it should be)
When constructing your classes as you describe it you can have a look at the creational design patterns.
Your second proposed solution is almost a builder design pattern. This will help you to construct the Slot e.g. piecewise.
As an example:
#include <iostream>
class Slot {
public:
int GetMinWidth() const { return min_width_; };
int GetMaxWidth() const { return max_width_; };
// Builder class
class SlotBuilder {
public:
SlotBuilder& SetMinWidth(int min_width) {
min_width_ = min_width;
return *this;
}
SlotBuilder& SetMaxWidth(int max_width) {
max_width_ = max_width;
return *this;
}
Slot Build() {
return Slot(min_width_, max_width_);
}
private:
int min_width_{/* you can add default value here*/};
int max_width_{/* you can add default value here*/};
};
// This is optional, but creates a neat interface
static SlotBuilder Create() {
static SlotBuilder slot_builder;
return slot_builder;
}
private:
// Make constructor private to restrict access and force the use of the builder
Slot(int min_width, int max_width) : min_width_(min_width), max_width_(max_width) {}
const int min_width_;
const int max_width_;
// .
// .
// Continue with your const attributes
};
int main() {
// Create the slot with the builder
Slot slot = Slot::Create()
.SetMinWidth(10)
.SetMaxWidth(20)
.Build();
std::cout << slot.GetMinWidth() << ", " << slot.GetMaxWidth();
return 0;
}
You can see the example working here
For having different types that are almost the same a Prototype pattern could work if you want to "clone" a class or in your case a Factory pattern could do the job.
There is never an ideal solution or that one pattern that solves it all, so I can't give you a definitive answer, but here are some collected thoughts:
Default values
Primitive types like int don't have a default value, so make sure you give them one explicitly:
struct Parcel {
int width{};
int height = 0;
int length = {};
int weight{};
}
All those different versions above are equivalent, but you really should use one of them. Otherwise you will probably run into UB down the line.
Const correctness
One thing that I love about C++ and that I dearly miss in languages like C# is const correctness. If you want an object to be immutable, declare it as const. To prevent changes to your objects, either instantiate the object as a const:
const Parcel x;
x.width = 10; // compiler error
or make the members of your classes const:
struct Parcel {
const int width{};
const int height{};
const int length{};
const int weight{};
};
Parcel x;
x.width = 10; // compiler error
Aggregate initialization
If you keep your types simple enough you can initialize the class members with curly braces directly:
const Parcel x { 1, 2, 3, 4 };
In C++ 20, you can also name the members, so this code is equivalent to the line above:
const Parcel x { .width = 1, .height = 2, .length = 3, .weight = 4 };
Note that this can bite you later though if you have to deal with ABI stability and versioning. In that case you are better off using getter and setter functions, because that allows you to still change the data layout of your members.
I have to think about design patterns a bit more. I'll update this post if something useful comes out of it.

Change base class from derived class permanently?

So, my problem is that i want to modify my parent class Board from a derived class in such a way that it applies to all other objects of the derived class. Ex. If I input a 3 on getTest() in players[1] players[2] will be able to print that same value. Is this posible?
class Board {
public:
int test;
virtual void getTest() = 0;
};
class Player : public Board{
public:
int playerNum;
Player(int _playerNum){
playerNum = _playerNum;
}
void printTest(){
cout << "The value of test is: " << Board::test;
}
void getTest(){
cin >> Board::test;
}
};
int main(){
Player players[] = {1,2};
players[1].getTest();
players[0].printTest();
return 0;
}
It is indeed possible to share state between all instances that derive from Board.
As mentioned in the comments, if Board::test were given the static storage-class duration, this would be a variable shared across all instances of Player and any other classes that derive from Board now and forever. Technically, the variable is actually a member of the type rather than instances of the type. This will work, however in terms of design, it has some strange implications.
Namely, Player::getTest() is a non-static member-function, which sets static state that will be shared across all derived classes of Board. This can work as a quick and dirty change to code, but can lead to maintenance burdens and cognitive overhead. For example, if you have code in different subsystems like a Player and Widget that both implement Board, you get into a case where:
// subsystem A:
player.getState();
// subsystem B:
widget.printTest(); // not obvious that this comes from the player in "subsystem A"
The bigger the code gets, the harder it is to understand.
Additionally, static variables have issues working across translation units that can lead to initialization-order problems -- and it's often a mess that's not worth fighting with.
Depending on what it is you actually intend to share, often times it can be better for design to explicitly state as such using an object that explicitly indicates its shared ownership -- such as a std::shared_ptr.
This won't be implicitly passed to everything as you originally requested -- but that's actually a good thing since you can explicitly state what data you want shared and where. This also lets you decide if ever there's a case where you don't want everything shared between them, you can design it as such.
A simple example with your current code would instead be done like:
class Board {
public:
virtual void getTest() = 0;
};
class Player : public Board{
public:
int playerNum;
std::shared_ptr<int> test;
Player(int _playerNum, std::shared_ptr<int> _test){
playerNum = _playerNum;
test = _test;
}
void printTest(){
cout << "The value of test is: " << *test;
}
void getTest(){
cin >> *test;
}
};
int main(){
std::shared_ptr<int> test = std::make_shared<int>(0);
// explicitly share 'test' between the two players
Player players[] = {Player{1,test}, Player{2,test}};
players[1].getTest();
players[0].printTest();
return 0;
}
This would produce the same results as you originally requested, but it explicitly shared test rather than implicitly doing this behind static variables.
Explicitly stating the shared state here also allows you to produce more Player objects later that might share a different set of test state than the first created ones (depending on what this state is, this can be quite useful).
Overall, it's often better in terms of design for readability and overall cognitive overhead to be explicit about the data you want shared.

c++ How to make changes to the same object across multiple classes?

Noobie here. I'm trying to make changes to the Player object mainCharacter across multiple classes. I currently have a Player object declared as seen below. The Player is able to teleport to various worlds and fight monsters.
All of that code works. Once the enemy of one world is defeated, they stay defeated. My problem is that when he teleports to another world, the Player's stats are all reset to their default values; he has full life points again even after sustaining damage from the enemy in the previous world.
How do I make changes to the same Player object across multiple classes, or worlds? I figure there's a problem in my declarations but I'm not sure. I appreciate any input. Thanks!
Where the mainCharacter object is declared:
class SpaceList
{
protected:
class SpaceNode
{
friend class SpaceList;
Player mainCharacter;
Space* thisSpace;
SpaceNode* next;
SpaceNode(int m, SpaceNode* next1 = NULL)
{
if(m == 0)
{
thisSpace = new EntranceHall(&mainCharacter);
}
else if(m == 1)
{
thisSpace = new WaterSpace(&mainCharacter);
}
Part of Player.hpp:
class Player: public Interactable
{
protected:
Backpack myBackpack;
public:
Player();
virtual interactableType getInteractableType();
virtual int interact();
virtual int attack();
virtual void defend(int);
Part of Player.cpp:
Player::Player()
{
healthPoints = 10;
numberOfAttackDice = 1;
sidesOfAttackDice = 6;
numberOfDefendDice = 1;
sidesOfDefendDice = 6;
}
mainCharacter starts off at Entrance (Entrance.cpp):
EntranceHall::EntranceHall(Interactable* mainCharacter)
{
interactableGrid[6][3] = mainCharacter;
interactableGrid[0][3] = new Portal(0);//entrance portal
interactableGrid[3][3] = new InterestPoint(0);//stone mural
}
mainCharacter may later teleport to Water World, default values reset (Waterspace.cpp):
WaterSpace::WaterSpace(Interactable* mainCharacter)
{
interactableGrid[3][0] = mainCharacter;
interactableGrid[3][3] = new Boss(this->getSpaceType());
Remove the has-a relationship between SpaceNode and Player - create an instance of Player somewhere outside and use a pointer to refer to it, like you're used to. Or just make it static, so that there's only one instance that does not get reconstructed (or rather constructed separately for each SpaceNode).
Notes:
Don't implement linked lists yourself, this data structure does not even fit here. Try std::vector.
Better switch to smart pointers. You might be leaking memory without even knowing it.

Accessing and changing parent values from subclass instances

I am a beginner and tryed to find an answer on this website but I was not able to figure out how to solve my specific C++ OOP problem.
Short: I want to access and change values of a parent class from subclass instances, but somehow my approach seems not to be working.
Example: There are many Car instances in my program (created with new construct). If one of the Car objects detects a collision, all Car instances should inverse their movement. The Car that registered the collision should call the parents' ChangeSpeed method or change the speed value directly.
Problem: the speed variable seems not to be updated. Is there something wrong with this particular code/ approach or do I have to search for my problem somewhere else?
// SpeedControl.h ------------------------------
class SpeedControl
{
public:
void ChangeSpeed(int);
protected:
int speed;
};
class Car:
public SpeedControl
{
public:
void MoveCar();
void DetectCollision();
private:
int position;
};
// SpeedControl.cpp ------------------------------
#include SpeedControl.h
SpeedControl::SpeedControl(void)
{
speed = 10;
}
SpeedControl::~SpeedControl(void)
{
}
SpeedControl::ChangeSpeed(int _value)
{
speed *= _value;
}
// Car.cpp ------------------------------
#include SpeedControl.h
Car::Car(void)
{
position = 100;
}
Car::~Car(void)
{
}
Car::MoveCar()
{
position += speed; // speed should be accessible?
}
Car::DetectCollision()
{
speed *= (-1); // inverse speed variable in parent class to inverse direction of ALL cars
// alternative:
// ChangeSpeed(-1); // call parent function to inverse speed
}
This looks like a problem where the observer pattern is the right solution.
You should implement a GetSpeed() in your SpeedControl class, which returns the current speed.
Then you can use this in MoveCar function:
ChangeSpeed(GetSpeed() + GetSpeed()); // Assuming you want to double the speed.
and in your collision:
ChangeSpeed(-GetSpeed());
Alternatively, you could make "ChangeSpeed" a multiplication rather than an addition.
You didn't state what exactly is wrong with your code, but from glancing on it, you're using private inheritance, which hides all parent's members from derived classes.
class Child : public Parent { };
The line above will ensure that the Parent members are accessible from Child.
You seem to misunderstand inheritance. What you need is a static variable.
Define static int speed in Car class. You can drop SpeedControl class.

Best way to alias methods of member object? "Passthrough methods"

Consider the following code:
class Rectangle
{
public:
// Constructors
Rectangle(){ init(0,0); }
Rectangle(int h, int w){ init(h,w); }
// Methods
void init(int h, int w)
{
_h = h;
_w = w;
}
// Getters / Setters
double get_h(void){ return _h; }
double get_w(void){ return _w; }
void set_h(double h){ _h = h; }
void set_w(double w){ _w = w; }
std::string get_name(void){ return _name; }
void set_name(std::string name){ _name = name; }
private:
// Private Members
int _h, _w;
std::string _name;
};
class House
{
public:
// <BEGIN PASSTHROUGHS>
std::string get_b_name(void){ return _base.get_name() };
std::string get_r_name(void){ return _roof.get_name() };
void set_b_name(std::string name){ _base.set_name(name); }
void set_r_name(std::string name){ _roof.set_name(name); }
// </END PASSTHROUGHS>
private:
// Private Members
Rectangle _base;
Triangle _roof;
};
This code works fine.
My question deals with the "passthrough" functions in the House class, enclosed by the PASSTHROUGHS tags. Is this the best way to do this? The arguments and return types will always match and there is no "intelligence" in these passthrough functions other than to make things cleaner and more straightforward.
My instinct would be something like one of the following:
get_b_name = _base.get_name;
// OR
std::string get_b_name(void) = _base.get_name;
... but neither seem to work unfortunately and it was only wishful thinking in the first place. If there are no easier options, telling me that is fine too. Thanks!
The problem, I think, is conceptual. Your design is quite un-object oriented in that the house does not represent an entity, but rather provides a bit of glue around the components. From that standpoint, it would make more sense to provide accessors to the elements, rather than pass-through functions:
class House {
Rectangle _base;
Triangle _roof;
public:
const Rectangle& base() const {
return _base;
}
const Triangle& roof() const {
return _roof;
}
};
I imagine that this is just a toy example, but the same reasoning applies: a class should represent an entity on which a set of operations are preformed, in some cases those operations might be implemented in terms of internal subobjects, but they are still operations on the type, and how they are gathered is an implementation detail.
Consider:
class House {
Thermostat t;
public:
int temperature() const {
return t.temperature();
}
};
From the user point of view the house has a temperature that can be read, and in this particular implementation, it is read from a thermostat that is a member. But that is an implementation detail. You might want to later install more thermostats in the house and substitute the single reading by an average of the readings, but that will not change the fact that the entity House (in this model) has a temperature.
That is, you should not be thinking in implementing pass-through functions, but rather on implementing features of the type. If the implementation happens to be a single forwarding to an internal method, that is fine.
But if the type contains internal members and it makes sense to access properties of the members, consider that it might be that you actual type should just provide access to its internal members. Consider that you want to move a piano inside the house, then you might just provide access to the door member and let the user check:
class House {
Door d;
public:
Door const & door() const {
return d;
}
};
bool can_enter_piano( House const & h, Piano const & p ) {
return h.door().width() > p.size();
}
There is no need to provide House::get_door_width(), and House::get_door_color() so that you can describe the entrance to a friend, and House::get_door_handle() so that they can know when they arrive...
That's possibly because your design is contradictory. Why on earth would you make a public member variable, then write a function that just forwards to one of that variable's functions? As a user of your class, I'd just call the function on the public variable myself. You're just confusing me by providing two ways to do the same thing. Or write getters and setters for a Rectangle class? That thing is just a bunch of variables, and doesn't need any getters and setters. You're not exactly going to inherit from it, and you can't really change the internal logic and maintain the same semantics, so it's very meaningless to not just make the variables public.
The Rectangle class needs a very healthy dose of YAGNI, and the House class just needs to look at itself again. The fact that there's no intelligence in the "passthrough" methods should be a huge alarm bell telling you that they are quite probably redundant and not helpful- especially since you can't change the public variables without breaking your interface anyway, it's not like the getters and setters are decreasing coupling or anything like that.
Methods should perform logic, or in the very least case, exist where logic might have to be done.