I wanted to create an array where each element can be either set from an int or float (these particular types are just an example).
So I went ahead and made a class with two constructors:
class ScaledNumber {
private:
int scaled_number;
public:
ScaledNumber(int number);
ScaledNumber(float number);
};
ScaledNumber::ScaledNumber(int number) {
scaled_number = number * 1000;
}
ScaledNumber::ScaledNumber(float number) {
scaled_number = (int)(number * 1000);
}
This works fine when I work with a single variable of this class. But now I want to create an array of such objects. I had to add a third constructor to even get the declaration working:
ScaledNumber::ScaledNumber() {}
ScaledNumber numbers[5];
Now if I want to re-assign for example numbers[3], can I somehow make use of the constructor or do I have to add a set() method or something like that?
can I somehow make use of the constructor
You can simply use:
ScaledNumber numbers[5];
numbers[0] = 20;
numbers[1] = 30.2f;
The compiler will use the appropriate constructor before making the assignment. The last two lines are translated by the compiler to:
numbers[0] = ScaledNumber(20);
numbers[1] = ScaledNumber(30.2f);
What's the point of ScaledNumber numbers[5]; anyway? You previously didn't need ScaledNumber number; for a single object to work, presumably because it didn't make sense to create such a half-ready object, so why would you need it for five objects?
You can just initialise the objects in the array like this:
#include <iostream>
class ScaledNumber {
private:
int scaled_number;
public:
ScaledNumber(int number);
ScaledNumber(double number);
};
ScaledNumber::ScaledNumber(int number) : scaled_number(number * 1000) {
std::cout << "int\n";
}
ScaledNumber::ScaledNumber(double number) : scaled_number(static_cast<int>(number * 1000)) {
std::cout << "double\n";
}
int main() {
ScaledNumber numbers[] = { 1, 2.2, 3, 4.4, 5 };
}
Output:
int
double
int
double
int
Note that I also made four improvements: I replaced float with double (the default floating-point type of the language), turned the C-style cast into static_cast, I added initialisation lists to the constructors and I made the compiler count the elements in the array.
Related
I am getting an error when I am trying to erase an object from my vector
googled but I can't understand what's wrong. from what I gathered I am calling the erase function correctly but I have to provide a move assignment operator to my classes?
my function where i call the erase
void removegroup(const short &group){
switch (tracker[group].group){
case 0: {
guardvec.erase(guardvec.begin()+tracker[group].position); //this is the problem it compiles just fine if i comment out this line
//guardvec.erase(remove(guardvec.begin(), guardvec.end(), tracker[group].position),guardvec.end()); //tried this and it doesnt work
}
break;
}
for (short counter=0;counter<tracker.size();counter++)
if ((tracker[counter].group==tracker[group].group)&&(tracker[counter].position>tracker[group].position))
tracker[counter].position=tracker[counter].position--;
}
my class
class guardhitdice {
friend class guard;
short const times = 2, dice = 8, plus = 2;
};
class guard : private guardhitdice {
private:
short units, XP, morale, totalHP=0, dead=0, wounded=0;
short* HP = new short[units];
public:
void showstats(){
std::cout << "STR=1, DEX=1, CON=1, INT=0, WIS=0, CHA=0, Perception=2, Passive Perception=12"<<std::endl
<<"current xp: "<<XP<<"total HP across units: "<<totalHP<<"casualties: "<<dead<<"wounded: "<<wounded;
}
void initializeHP(){
for (short counter=0; counter<units-1; counter++){
HP[counter]=plus + D(times, dice);
totalHP+=HP[counter];
}
}
guard(const short &xp, short &Units, short &Morale){
XP=xp;
units=Units;
morale=Morale;
// short* HP = new short[units];
initializeHP();
}
~guard(){
delete HP;
}
};
here is my compiler error https://pastebin.com/KSniFkVD
it should be able to remove the object at tracker[group].position. btw position is a short
i also tried adding this to my classes but they don't work
guardhitdice& guardhitdice ::operator=(guardhitdice&&);
guard& guard ::operator=(guard&&);
it works if I do it for normal vectors but not for vectors of objects
Your problem can be reduced down to
#include <vector>
class test{
short const times = 2;
};
int main()
{
std::vector<test> t;
t.push_back(test{});
t.erase(t.begin()); //<-- BAM!
}
Example: https://ideone.com/MlwUyI
vector does a lot of copy-and-assigning. Copying is cool, but test contains a const member. You can't change a const variable, so you can't assign it.
But since it's initialized with a literal and there's no constructor that'll allow the value to be initialized to something else, all instances of test will have the same value. That's a pretty good fit for static. static variables don't take part in assignment, so the default assignment operator is usable.
class test{
static short const times = 2;
};
Example: https://ideone.com/npUi4B
For example:
const int m = 10;
class C{
public:
double A[m];
};
int main(){
C name;
name.A[m] = ... // initializing here?
}
I can't find a way around that, I could for example do
C name = {...};
Which would perfectly work but for the sake of functionality I wanna know if I can do that for single variables inside the class.
In your example, you only need to write:
name.A[x]=value;
Where value is double and x is between 0 and 9. You can also make a loop if you wish to set values for all or some of its elements.
I want know how I can add values to my vector of structs using the push_back method
struct subject
{
string name;
int marks;
int credits;
};
vector<subject> sub;
So now how can I add elements to it?
I have function that initializes string name(subject name to it)
void setName(string s1, string s2, ...... string s6)
{
// how can i set name too sub[0].name= "english", sub[1].name = "math" etc
sub[0].name = s1 // gives segmentation fault; so how do I use push_back method?
sub.name.push_back(s1);
sub.name.push_back(s2);
sub.name.push_back(s3);
sub.name.push_back(s4);
sub.name.push_back(s6);
}
Function call
setName("english", "math", "physics" ... "economics");
Create vector, push_back element, then modify it as so:
struct subject {
string name;
int marks;
int credits;
};
int main() {
vector<subject> sub;
//Push back new subject created with default constructor.
sub.push_back(subject());
//Vector now has 1 element # index 0, so modify it.
sub[0].name = "english";
//Add a new element if you want another:
sub.push_back(subject());
//Modify its name and marks.
sub[1].name = "math";
sub[1].marks = 90;
}
You cant access a vector with [#] until an element exists in the vector at that index. This example populates the [#] and then modifies it afterward.
If you want to use the new current standard, you can do so:
sub.emplace_back ("Math", 70, 0); // requires a fitting constructor, though
or
sub.push_back ({"Math", 70, 0}); // works without constructor
.
You may also which to use aggregate initialization from a braced initialization list for situations like these.
#include <vector>
using namespace std;
struct subject {
string name;
int marks;
int credits;
};
int main() {
vector<subject> sub {
{"english", 10, 0},
{"math" , 20, 5}
};
}
Sometimes however, the members of a struct may not be so simple, so you must give the compiler a hand in deducing its types.
So extending on the above.
#include <vector>
using namespace std;
struct assessment {
int points;
int total;
float percentage;
};
struct subject {
string name;
int marks;
int credits;
vector<assessment> assessments;
};
int main() {
vector<subject> sub {
{"english", 10, 0, {
assessment{1,3,0.33f},
assessment{2,3,0.66f},
assessment{3,3,1.00f}
}},
{"math" , 20, 5, {
assessment{2,4,0.50f}
}}
};
}
Without the assessment in the braced initializer the compiler will fail when attempting to deduce the type.
The above has been compiled and tested with gcc in c++17. It should however work from c++11 and onward. In c++20 we may see the designator syntax, my hope is that it will allow for for the following
{"english", 10, 0, .assessments{
{1,3,0.33f},
{2,3,0.66f},
{3,3,1.00f}
}},
source: http://en.cppreference.com/w/cpp/language/aggregate_initialization
You cannot access elements of an empty vector by subscript.
Always check that the vector is not empty & the index is valid while using the [] operator on std::vector.
[] does not add elements if none exists, but it causes an Undefined Behavior if the index is invalid.
You should create a temporary object of your structure, fill it up and then add it to the vector, using vector::push_back()
subject subObj;
subObj.name = s1;
sub.push_back(subObj);
After looking on the accepted answer I realized that if know size of required vector then we have to use a loop to initialize every element
But I found new to do this using default_structure_element like following...
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
typedef struct subject {
string name;
int marks;
int credits;
}subject;
int main(){
subject default_subject;
default_subject.name="NONE";
default_subject.marks = 0;
default_subject.credits = 0;
vector <subject> sub(10,default_subject); // default_subject to initialize
//to check is it initialised
for(ll i=0;i<sub.size();i++) {
cout << sub[i].name << " " << sub[i].marks << " " << sub[i].credits << endl;
}
}
Then I think its good to way to initialize a vector of the struct, isn't it?
#include <iostream>
using namespace std;
class t
{ public:
int health; //its members
int speed;
int power;
void attack() // its methods
{ cout<<"I'm attacking"<<endl;
};
};
int main()
{ t A,B,C,D;
A.power = 100;
B.health = 87;
C.speed = 92;
cout<<"A= "<<A.power<<"B= "<<A.health<<"C= "<<A.speed<<endl; // <---
cout<< "My health is "<<C.health<<" My speed is "<<A.speed<<endl;
cout<<"My power is "<<B.power<<endl;
D.attack();
system("pause");
return 0;}
The output result was ::
A= 100 B= 96 C=6234392 <--- From where these values come
A.health and A.speed are just junk values on the stack because you didn't explicitly set them. If you want to initialize all fields of A to zero, you can use memset:
memset(&A, 0, sizeof(A));
You should create a constructor to initialize those values to some default value in the initializer list.
class t {
public:
t() : health(100),power(100),speed(100) {}
// ...
};
This will guarantee that those values are all set to 100, or some default, or even an input parameter, rather than garbage. It's considered much better design since otherwise the initialization of those values would be handled in the constructor that the compiler generates for you behind the scenes.
Uninitialized memory?
Uninitialized variable won't be zero setted at the creation of the class/struct. You need to manualy do it. Otherwise, you will get whatever_is_in_memory_at_that_time.
I'm having this problem for quite a long time - I have fixed sized 2D array as a class member.
class myClass
{
public:
void getpointeM(...??????...);
double * retpointM();
private:
double M[3][3];
};
int main()
{
myClass moo;
double *A[3][3];
moo.getpointM( A ); ???
A = moo.retpointM(); ???
}
I'd like to pass pointer to M matrix outside. It's probably very simple, but I just can't find the proper combination of & and * etc.
Thanks for help.
double *A[3][3]; is a 2-dimensional array of double *s. You want double (*A)[3][3];
.
Then, note that A and *A and **A all have the same address, just different types.
Making a typedef can simplify things:
typedef double d3x3[3][3];
This being C++, you should pass the variable by reference, not pointer:
void getpointeM( d3x3 &matrix );
Now you don't need to use parens in type names, and the compiler makes sure you're passing an array of the correct size.
Your intent is not clear. What is getpointeM supposed to do? Return a pointer to the internal matrix (through the parameter), or return a copy of the matrix?
To return a pointer, you can do this
// Pointer-based version
...
void getpointeM(double (**p)[3][3]) { *p = &M; }
...
int main() {
double (*A)[3][3];
moo.getpointM(&A);
}
// Reference-based version
...
void getpointeM(double (*&p)[3][3]) { p = &M; }
...
int main() {
double (*A)[3][3];
moo.getpointM(A);
}
For retpointM the declaration would look as follows
...
double (*retpointM())[3][3] { return &M; }
...
int main() {
double (*A)[3][3];
A = moo.retpointM();
}
This is rather difficult to read though. You can make it look a lot clearer if you use a typedef-name for your array type
typedef double M3x3[3][3];
In that case the above examples will transform into
// Pointer-based version
...
void getpointeM(M3x3 **p) { *p = &M; }
...
int main() {
M3x3 *A;
moo.getpointM(&A);
}
// Reference-based version
...
void getpointeM(M3x3 *&p) { p = &M; }
...
int main() {
double (*A)[3][3];
moo.getpointM(A);
}
// retpointM
...
M3x3 *retpointM() { return &M; }
...
int main() {
M3x3 *A;
A = moo.retpointM();
}
The short answer is that you can get a double * to the start of the array:
public:
double * getMatrix() { return &M[0][0]; }
Outside the class, though, you can't really trivially turn the double * into another 2D array directly, at least not in a pattern that I've seen used.
You could create a 2D array in main, though (double A[3][3]) and pass that in to a getPoint method, which could copy the values into the passed-in array. That would give you a copy, which might be what you want (instead of the original, modifiable, data). Downside is that you have to copy it, of course.
class myClass
{
public:
void getpointeM(double *A[3][3])
{
//Initialize array here
}
private:
double M[3][3];
};
int main()
{
myClass moo;
double *A[3][3];
moo.getpointM( A );
}
You may want to take the code in your main function which works with the 2D array of doubles, and move that into myClass as a member function. Not only would you not have to deal with the difficulty of passing a pointer for that 2D array, but code external to your class would no longer need to know the details of how your class implements A, since they would now be calling a function in myClass and letting that do the work. If, say, you later decided to allow variable dimensions of A and chose to replace the array with a vector of vectors, you wouldn't need to rewrite any calling code in order for it to work.
In your main() function:
double *A[3][3];
creates a 3x3 array of double* (or pointers to doubles). In other words, 9 x 32-bit contiguous words of memory to store 9 memory pointers.
There's no need to make a copy of this array in main() unless the class is going to be destroyed, and you still want to access this information. Instead, you can simply return a pointer to the start of this member array.
If you only want to return a pointer to an internal class member, you only really need a single pointer value in main():
double *A;
But, if you're passing this pointer to a function and you need the function to update its value, you need a double pointer (which will allow the function to return the real pointer value back to the caller:
double **A;
And inside getpointM() you can simply point A to the internal member (M):
getpointeM(double** A)
{
// Updated types to make the assignment compatible
// This code will make the return argument (A) point to the
// memory location (&) of the start of the 2-dimensional array
// (M[0][0]).
*A = &(M[0][0]);
}
Make M public instead of private. Since you want to allow access to M through a pointer, M is not encapsulated anyway.
struct myClass {
myClass() {
std::fill_n(&M[0][0], sizeof M / sizeof M[0][0], 0.0);
}
double M[3][3];
};
int main() {
myClass moo;
double (*A)[3] = moo.M;
double (&R)[3][3] = moo.M;
for (int r = 0; r != 3; ++r) {
for (int c = 0; c != 3; ++c) {
cout << A[r][c] << R[r][c] << ' ';
// notice A[r][c] and R[r][c] are the exact same object
// I'm using both to show you can use A and R identically
}
}
return 0;
}
I would, in general, prefer R over A because the all of the lengths are fixed (A could potentially point to a double[10][3] if that was a requirement) and the reference will usually lead to clearer code.