In C++ is it possible to change the default values of a class so that all future objects made of that class will have the values specified?
I am trying to make a class that is user-defined at run time that should function nearly identical to other child of the same parent class, but I am struggling with a way to have the same format constructor exist across both. The only way I can think to properly funnel the correct information to every new object is to have either the class type be always treated differently on creation (always put in the user inputs into the constructor) or have the class's object behavior on creation change to default to the inputs defined.
Edit: To better explain the issue and address the XY problem possibility here is the scenario:
General Program:
I want to have the user first define a custom shape by providing a name and the number of lines that define it. The user then can add triangles, squares and the custom shape to their "cart". Each custom shape is the same shape that they specified at the start, the user does not change it during the program. The program could then return general information such as the number of members of a specific type that exists or the total number of lines in the cart.
There is a parent class:
Class Shape
member numLines, name;
And three classes are children of Shape:
Class Triangle
overwritten numLines = 3, name = "triangle";
...
Class userShape
overwritten numline = ????, name = ????;
When I create methods for the cart that interact with "shape" objects I would like to be able to have the same code across the board for creating additional objects, instead of needing to treat the userShape's constructor differently.
From the answers I have received, the static type seems to best fit the user-setting of the default values but I am entirely open to better ways to implement something like this.
Just because you can, doesn't mean you should. Now that I got that out of the way, here's how:
#include <iostream>
struct C {
static int default_val;
C(int i = default_val) {
std::cout << i << '\n';
}
};
int C::default_val = 0;
int main() {
C c;
C::default_val = 1;
C c2;
return 0;
}
A default argument to a function doesn't have to be a constant expression, it just has to be "available" at every place the function is called. And a static variable is just that.
It also doesn't have to be accessible at the call site. So if you want the class to control it, but not have it be modifiable from outside the class, you can make it private.
I would recommend following the next pattern:
Run your application
Read/Load the configuration
Create a factory for that object from that configuration
Use the factory to create more instances of the same object throught the lifetime of your application
For example:
struct Object {
Object(int x, int y) : _x(x), _y(y) {}
int _x, _y;
};
struct DynamicFactory {
DynamicFactory(int x, int y) : _x(x), _y(y) {}
std::shared_ptr<Object> generate() { return std::make_shared<Object>(_x, _y); }
int _x, _y;
};
int main(){
// Load configuration
// Initialize dynamic factory using configuration
DynamicFactory factory(1, 3);
// Generate objects
auto obj1 = factory.generate();
auto obj2 = factory.generate();
return 0;
}
Try to use static members so these are shared across the objects.
Related
I have many function definitions which I have placed in different cpp files with function declarations in their respective .h files.
I have a set of a variables which I have placed in a .h file. These variables need to modified by different functions. I am using static to keep the changes from each function, but I heard it is a bad coding practice. How else to do it ? For eg -
variables.h
class variable{
static int x;
static int y;
};
function1.h
class function(){
public:
void function1();
}
similar for function 2
function 1.cpp
void function1(){
// does something with x and y (used as (variable::x=2;variable::y=3)
}
function2.cpp
void function2(){
// does something with x and y (used as variable::x+=2;variable::y+=2)
}
main.cpp
int variable::x;
int variable::y;
int main(){
obj.function1(); (obj is object of function1 class)
obj2.function2(); (obj2 is object of function2 class)
cout << variable::x << variable::y << endl;
}
I was was using different objects in different cpp files but changes in one function were not reflecting in other. How it use it please help?
You can simply move these variables into another class:
struct Shared {
int x;
int y;
};
Now you can pass an instance to this class as parameter to your function, this is called dependency injection:
void foo(Shared& shared) {
shared.x = 4;
shared.y = 2;
}
This is better because you don't have any global state anymore. You could use the function multiple times independent from each other by referencing a different instance of the Shared class.
It is very common to take this a step further by "injecting" the instance in the constructor of that class. This is helpful if the instance of that class should always reference the same instance:
struct Foo {
Shared& m_shared;
Foo(Shared& shared)
: m_shared(shared)
{
}
void foo() {
m_shared.x = 4;
m_shared.y = 2;
}
};
Yes, as you mentioned using static variable for this purpose is kind of anti-pattern. A better pattern (without knowing the background of the application) is using a composition pattern. If your functions f1() and f2() are in classes C1 and C2, you would e. g. create an additional data object D1 (with the variables in question), and inject and object of D1 in the constructor of C1 and C2, so both classes operation on a data object. There are also other solutions to this situation, but I guess thats the most general. Google for C++ Design Pattern to find more general patterns.
You can use smart pointers for global objects
struct MyGlobal
{
std::shared_ptr<Core> core;
MyGlobal(){ core=std::make_shared<Core>(); }
void changeVariableX(int X)
{
core->X = X;
}
};
You can move, copy, do whatever you want with MyGlobal instances and they still point to same core item. Just make sure all of them are populated from same instance like this:
int main()
{
MyGlobal global;
auto something = useSomeFunctionWith(global);
auto somethingElse = useAnotherFunctionWith(global);
...
// use something and somethingElse to change X, both point to the same X
}
If functions will not be thread-safe then you should add a lock-guard into changeVariableX method.
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.
I have a struct that needs to keep track of the number of created instances and uses it as a unique ID. Hence in the default constructor I need to update a static variable such as this:
struct Wire {
int x, y, id;
static int instanceCount;
this() {
this.id = instanceCount++;
}
}
I do not wish to disable the default constructor. Currently I am using a class to work-around it.
Those are your options in D. Use a class and be able to define no-argument constructors, or use a struct and not be able to do this. The reasons for it apparently have to deal with D's .init functionality. Another workaround would be to use a separate factory function that constructs Wire, updates instanceCount, and returns Wire.
What you're doing sounds like makes much more sense with classes, anyway. It's more expected for classes to have 'instances' and class state like instanceCount. If you only want structs so that you can allocate them on the stack, you can actually do this with classes: scope s = new S()
As #verne already point outyou should use classes for that. Another way is use static opCall, but it is not perfect solution:
import std.stdio;
struct Wire {
int x, y, id;
static int instanceCount;
static opCall() {
Wire w;
w.id = instanceCount++;
return w;
}
}
void main()
{
auto s0 = Wire();
auto s1 = Wire();
writeln(s0);
writeln(s1);
}
I would like to create objects of a class with the name of an input
class Rectangle {
public:
int width;
int height;
...
//assume a constructor that assigns (width, height)
}
how would i generate an object of a new name using an input. (not me typing Rectangle myRectangle(1,1); )
assume that there is anywhere from 1 to infinite objects created by the user
(i am not looking for help with the human input, or checking if they still want an input, solely how to use an input to create a uniquely named object)
this is my first stack overflow post so please inform me if i did something wrong.
Cheers,
Coal lad
You can use a map from (user supplied) class name to a factory function.
class Creatable {
virtual ~Creatable() {}
};
class Rectangle : public Creatable {
int width;
int height;
};
class Circle : public Creatable {
int radius;
};
// assume suitable constructors for these
// Given a string (with parameters such as the
// radius or width/height) construct an object
// and return a managed pointer to it
using FactoryFunction_t =
std::function<std::unique_ptr<Creatable>(std::string const &)>;
// maps for example "rectangle" to a function which parses width and height from the string and returns an allocated rectangle
std::map<std::string, FactoryFunction_t> factories;
factories.insert({{"rectangle", CreateRectangle}, {"circle", CreateCircle}});
factories.at("rectangle")("width=21; height=42;");
Instead of using polymorphism (a common base class) you can also use std::variant if the possible classes are known at compile time.
Instead of having each factory function parse a string you can also parse the parameters before - for example into a map parameter name -> parameter value and pass that to the factory functions.
If you want to let the user name the created objects then you could keep the managed pointers from above in a map:
std::map<std::string, std::unique_ptr<Creatable>> objects;
objects["my_rectangle"] = factories.at("rectangle")("width=21; height=42;");
This could be the result from input from the user similar to this:
my_rectangle = rectangle(width=21;height=42;);
#include<vector>
class Rectangle {
public:
int width;
int height;
};
int main(){
/*You can't use unique names. You can use a vector of objects
std::vector<Rectangles> rectsVector; and then when you want
to create anew object ask the user for (width,height) then
rectVector.push_back(Rectangle{width,height}) and so on*/
std::vector<Rectangle> rectsVector;
size_t width{3},height{2};
rectsVector.push_back(Rectangle{width,height});
return 0;
}
My teacher required us to create ID data member that's generated automatically, and once established it can’t be modified.
What is the most appropriate type?
if the answer is
static const int ID;
How can I generate it automatically while it's const?
Since the ID has to be unique, one shall make sure, that two instances never get the same ID. Also, noone outside class should interfere in generating the UID.
First, you define a static field in your class:
class Data
{
private:
static int newUID;
(...)
};
// The following shall be put in a .cpp file
int Data::newUID = 0;
Then, after each instance is created, it should take a new ID value and increment the newUID counter:
class Data
{
(...)
const int uid;
public:
Data()
: uid(newUID++)
{
}
int GetUid()
{
return uid;
}
};
Noone has access to internal newUID except the class, ID is generated automatically for each instance and you are (almost1) sure, that no two instances will have the same ID number.
1 Unless you generate a little more than 4 billion instances
Here is an example:
class SomeClass {
static int currID;
public:
const int ID;
SomeClass() :
ID(currID++) { // Initialization list used to initialize ID
}
};
And you must put this somewhere in your .cpp file:
int SomeClass::currId = 0;
This uses initialization lists to do the trick. We must do it this way for it is only in initialization lists where you can assign to a const member in an instance.
The core concept is that you must have a "global setting" to keep track of the ID that would be assigned to instances created in the future. It is currID in this example. For each instance created in your class, you assign the value of currID as the ID of that instance then increment it (currID). In this way, you get instances which have unique IDs.
create a const ID as int , initialize it in constructor initialization list like
SomeClass(): id(++staticIncrementingInt){
///other stuf here
}
Hope this helps.
You can actually call a function (rand, in this case) in the construction initialization list.
Up to you now how you can seed it.
If your teacher allows boost libs then try Boost.Uuid. An example is here. It is RFC 4122 compliant.