why would you want a structure in a class? [closed] - c++

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
Have homework and we just went over classes. Thinking about how I could implement classes into my homework but the instructions say use a structure. (It's reading binary files and editing information) After looking at some stuff we did in class I probably don't need classes for my situation. But now I'm curious, why would you want to use a structure inside a class? Why would you use a structure when you can just set the data members in the class instead? What does struct have to offer to warrant doing this?

The primary benefit of putting values into an inner struct as opposed to just declaring them as member variables of the class would be that you can then instantiate multiple instances of that struct very easily, and refer to the set of variables in each struct with a single pointer or reference.
As an example, here are two implementations of a toy array-of-3D-points class. The first one just uses separate member-variables, while the second one declares an inner struct to represent a Point object.
Note that in the first implementation, the RotatePoint() method takes four arguments, while in the seconds argument it takes just two. Being able to refer to a Point with a single struct Point & argument (rather than three separate float & arguments) is both more efficient at run-time and less error-prone for the programmer to call.
// implementation without an inner struct
class MyPointArray1
{
public:
[...]
void RotatePoints(float radians)
{
for (int i=0; i<POINTS_ARRAY_LENGTH; i++)
{
// Hazard here -- a tired programmer might specify arguments in the wrong order!
RotatePoint(x[i], y[i], z[i], radians);
}
}
private:
enum {POINTS_ARRAY_LENGTH = 100};
float x[POINTS_ARRAY_LENGTH];
float y[POINTS_ARRAY_LENGTH];
float z[POINTS_ARRAY_LENGTH];
void RotatePoint(float & x, float & y, float & z, float radians)
{
// [math to update the values of x, y, and z would go here]
}
};
// implementation with an inner struct
class MyPointArray2
{
public:
[...]
void RotatePoints(float radians)
{
for (int i=0; i<POINTS_ARRAY_LENGTH; i++)
{
// It's pretty much impossible to get this wrong without provoking a compile-time error :)
RotatePoint(points[i], radians);
}
}
private:
enum {POINTS_ARRAY_LENGTH = 100};
struct Point
{
float x;
float y;
float z;
};
struct Point points[POINTS_ARRAY_LENGTH];
void RotatePoint(struct Point & pt, float radians)
{
// [math to update the values in (pt) would go here]
}
};

From my understanding, you would implement a struct inside a class when you want to create objects within that class only. Outside of the class, you would not be able to create objects of that struct.

Related

How to overload constructors/functions when declarations/parameters are the same? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
I would like to create a class to manage the matrices and I met problem with the constructor.
The aim is to find the shortest way to call a constructor of a Matrix objet knowing that some of the constructors have the same header as staying clear.
This is the idea of what I try to get :
Matrix id; // create identity matrix
Matrix scale(x, y, z); // create directly a scale matrix
Matrix translation(x, y, z) // create a translation matrix
...
Here, all the parameters are floats so I cannot overload the constructor, the only thing I see is to use templates but only for those special cases then I don't know what to do.
Solution
Finally I decided to make an abstract class like this :
class _Mat
{
public :
virtual ~_Mat(void) = 0;
// ...
}
class Mat : public _Mat
{
public :
Mat(void);
virtual ~Mat(void);
class Scale : public _Mat
{
public :
Scale(float x, float y, float z);
vitual ~Scale(void);
// ...
}
// ...
}
All will be defined into _Mat and the other class will just be usefull for their constructor(s)
Finally, we can call constructors like this :
Mat id;
Mat::Scale scale(2, 2, 2);
// ...
You could keep it simple and use static member functions:
struct Matrix
{
// ...
static Matrix Translate(float x, float y, float z) {/*...*/}
static Matrix Scale(float x, float y, float z) {/*...*/}
};
// ...
Matrix m = Matrix::Scale(1,2,3);
You are looking for tag dispatching. You can see it used in the standard library, for example in the overloads of std::pair's constructor.
You just have to declare a "tag" struct, which is used to guide overload resolution:
struct translation_matrix_tag_t {} static translation_matrix_tag;
struct scale_matrix_tag_t {} static scale_matrix_tag;
And then overload your constructors:
struct Matrix {
Matrix(translation_matrix_tag_t, float, float, float);
Matrix(scale_matrix_tag_t, float, float, float);
// ...
};
Then you can use it like this:
void foo() {
Matrix m1{translation_matrix_tag, x, y, z};
Matrix m2{scale_matrix_tag, x, y, z};
}
You have the following options:
Introduce different dummy parameters of different types in the constructors to differentiate between the overloads. It is hacky, I would not recommend it.
Use inheritance. Create different subclasses where each one of them is named after the functionality provided by its constructor.
Make your constructor private and introduce public static factory methods that have nice and long names that clearly indicate what they do. (No overloading.)
Personally, I would go with the 3rd choice.

What is this construct: "void dot::print(void){"? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I came across this code, and I was interested what the constructs marked below by comments //<-- This are.
If it has a name then I would like to know (to google it and get more info if possible).
#include <stdio.h>
typedef struct point {
float x,y;
void print(void);
} dot;
typedef struct rect {
dot pt1,pt2;
float area(void);
dot center(void);
void print(void);
} rectangle;
void dot::print(void){ //<-- This
printf("(%3.1f,%3.1f)", x, y);
}
void rectangle::print(void){ //<-- This
pt1.print(); printf(":"); pt2.print();
}
dot rectangle::center(void){ //<-- This
dot c; c.x=(pt1.x + pt2.x)/2;
c.y=(pt1.y + pt2.y)/2; return c;
}
float rectangle::area(void){ //<-- This
return((pt2.x-pt1.x)*(pt2.y-pt1.y));
}
They are implementations of the functions defined in the classes (structs) abouse. Usually though, you would do this in your cpp file, so you would have your h file with:
class Foo{
int method1();
int method2();
}
and then in your cpp file you would add the implementation using:
int Foo::method1(){
....
}
This code is a bit silly though, because the classes are defined in ye olde c way using the typedef struct syntax. This would make sense in some cases, because c code is also valid c++ so you could have code that compiled as both. However c++ is not always valid c and this code id definitely c++ because of the member functions, so there is no point in using the typedef struct syntax. It is probably old code that has been modified.
The lines you are pointing to refer to the declaration of a function. I will explain one of these lnes, because you can apply the same lgic to the rest of them.
Let's look at the line:
void dot::print(void){
The first word in this line, void, defines the type of data returned fromthe function. Since it is void, no value is returned from this function, which is evident fomthe fact that there is no return statement in the entire function.
void dot::print(void) {
printf("(%3.1f,%3.1f)", x, y); // this is the last line of the function. This function does not pass on any value or data
}
Next is dot::, which is an object of struct point. If you see after the closing } of the struct point, you wil see that dot is declared here.
For the object dot, there is a function declaration called print(). This function is defined here, but since we have to indicate that we have to indicate that print() is a member of dot, we add the dot:: before the print(void) in the declaration.
Lastly is the void in parenthesis. This simply means that the function has no input parameters from the function that has called it; in other words, it does not need any data from outside the function.
Just as a recommendation, your code is more c than c++. You would be better off tagging this question as c instead of c++.

Initialise complex object [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 7 years ago.
Improve this question
What options are available to create an object with lots of parameters in the global namespace? I'm thinking of the tradeoff between temporary object/variable creation and readability.
Edit
This is for embedded programming on the Arduino. It will be the main object of a reusable library controlling a set of nested objects.
Background: I have a test PCB which can be populated differently depending on its final use and I need to cover all of these options in one easy to use library. I am trying to avoid the user accidently missing required initialisation parameters before using the object.
Feel free to constructively criticise my code!
The two options that I can think of are:
A constructor with lots of parameters.
A constructor with a single struct parameter.
Option 1 looks messy and hard to follow with lots of parameters.
Option 2 requires a temporary struct variable for readability.
Example below (normally I would separate into headers etc.):
#include <Arduino.h>
class NestedClass {
public:
// Empty constructor for creation of unitialised object. Bad practice?
NestedClass() {
}
// Main constructor.
NestedClass(float voltageReference) :
voltageReference_(voltageReference) { // Use initialisation list.
}
float measureVoltage(uint_fast8_t channel) {
// Convert ADC value to absolute voltage.
return analogRead(channel) * (voltageReference_ / 1023);
}
private:
float voltageReference_;
};
class ComplexClass {
public:
enum class Mode
: uint_fast8_t {
MODE1,
MODE2,
MODE3
};
struct Parameters {
uint_fast8_t parameter1;
uint8_t parameter2;
float parameter3;
float parameter4;
Mode mode;
float voltageReference;
};
// Empty constructor for creation of unitialised object. Bad practice?
ComplexClass(void) {
}
// Big constructor. Messy when used.
ComplexClass(uint_fast8_t parameter1, uint8_t parameter2, float parameter3,
float parameter4, Mode mode, float voltageReference) {
// Could have used initialisation list instead.
this->parameter1_ = parameter1;
this->parameter2_ = parameter2;
this->parameter3_ = parameter3;
this->parameter4_ = parameter4;
this->mode_ = mode;
this->nestedClass_ = NestedClass(voltageReference); // Wasted temporary object with reassignment?
}
// Alternative constructor. Looks neater/more legible when used.
ComplexClass(Parameters parameters) {
this->parameter1_ = parameters.parameter1;
this->parameter2_ = parameters.parameter2;
this->parameter3_ = parameters.parameter3;
this->parameter4_ = parameters.parameter4;
this->mode_ = parameters.mode;
this->nestedClass_ = NestedClass(parameters.voltageReference); // Wasted temporary object with reassignment?
}
void megaMeasurements() {
// Do something involving nestedClass.measureVoltage().
}
private:
// Maybe put all of these in another struct for neatness?
uint_fast8_t parameter1_;
uint8_t parameter2_;
float parameter3_;
float parameter4_;
Mode mode_;
NestedClass nestedClass_;
};
//####################
// Start main code.
//####################
// Option 1:
// Not immediately obvious which value is for which parameter.
ComplexClass complexClass(1, 2, 3.30, 2.7, ComplexClass::Mode::MODE2, 5.00);
// Option 2:
// Unitialised object (sort-of).
ComplexClass complexClass2;
// Arduino standard function. Called once from main.cpp
void setup() {
// Option 2 continued:
ComplexClass::Parameters parameters;
parameters.mode = ComplexClass::Mode::MODE2;
parameters.parameter1 = 1;
parameters.parameter2 = 2;
parameters.parameter3 = 3.30;
parameters.parameter4 = 2.7;
parameters.voltageReference = 5.00;
complexClass2 = ComplexClass(parameters); // Reassignment. Wasteful?
}
// Arduino standard function. Called in a continuous loop after setup().
void loop() {
complexClass.megaMeasurements();
complexClass2.megaMeasurements();
}
My opinion (based on my practice):
constructor with many parameters look messy and should better be avoided. More, if some parameters are bad, you can't return "false" and the only way to complain is to throw an exception. If you want to go this way, it's better to define some init() function with several parameters, optionally returning false (or some error code) to complain if parameters are bad. In this case it's better to avoid literal numeric values using #define or static const declarations.
The other way is to assign values one by one, either directly (public) or with set() methods. In this case you can put literals in the code.

How to specify a type parameter using <> to create a template class [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I have this code:
class Grid {
public:
vector<vector<int> > grid;
int width;
int height;
Grid (int width, int height) width(width), height(height) {
...
}
};
It makes a class called Grid which is a 2D array of integers. The problem is, however, that at the moment it can only be integers, but I want it so it's kind of like the std::vector class in which you can use <> parentheses to choose the type that it will store. My question is, how can I use these in my class in order to replace all the current ints with any other class.
Also, you might say to look it up but I tried and I could't find anything, probably because I didn't know what to search so if anyone could give me an idea on what this is even called then that'd be helpful too.
It seems like you just want to template your Grid class:
template <typename T>
class Grid {
public:
vector<vector<T> > grid;
// initialize the vector with the correct dimensions:
Grid (int width, int height)
: grid(width, vector<double>(height)) {}
};
and then instantiate:
Grid<double> g(x, y);
This will create a Grid object where T is double

Differentiating between data class and logic class in agile [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 years ago.
Improve this question
I've been reading an agile book about clean coding, mainly in Java and c#. Considering the concept of differentiating between a data class and a logic/object class. I have the following situation in c++, where I can't decide which variant is a clean code. I have a Plane class with some attributes and these attributes change when only one of them changes, so
First Method
class Plane3D {
public:
BBox bbox;
float l,w,h;
void setbbox(BBox bbox) {
this->bbox = bbox;
recalculateLWH();
}
void setLWH(float l, float w, float h) {
//set here
recalculateBBOX();
}
};
This makes sense to me, since to the user he is just calling one method and doesn't have to care about internal work of the class. but this is a violation for a data class, that it contains logic
Now the
Second method
class Plane3D {
public:
BBox bbox;
float l,w,h;
void setbbox(BBox bbox) {
this->bbox = bbox;
}
void setLWH(float l, float w, float h) {
//set here LWH
}
};
int main() {
BBox bbox;//init here
Plane plane;
plane.setBBox(bbox);
recalculateLWH(plane);
}
Now the second method actually separates the data class from the implementation but it increases the responsibilities of the class user and forces him to make an extra call. To my understanding the second method is the correct one from an agile POV, but I find the first method more logical to use.
I'd like to know which of the two methods would make more sense for you guys to undertsand and use
Regards
In this case I think you should prefer first method to second.
Your method calls should transform object from one correct state to another correct state. Using the second method after your setBBox(bbox); call your object moves to some incorrect state indeed.
But 'logic class way' can however take place in another situation.
Consider you should move plane:) from hangar to landing strip. Now it will be naturally to introduce new class named Tractor and use it like tractor.move(plane)