How do I initialize an array of objects from a function? I'm aware the code below is impractical; I'm just teaching myself C++.
Here is a structure that contains data.
struct pointStruct {
int numberPoints;
Point2D pointArray;
};
The Point2D class has instance variables x and y. In a separate function, I have:
void setPoints(void) {
pointStruct myPointData;
myPointData.numberPoints = 4;
myPointData.pointArray[4]; // here is the problem
// loop with i
myPointData.pointArray[i].x = ...;
myPointData.pointArray[i].y = ...;
}
I'm trying to initialize the array so that I can loop through it and set the x,y coordinates. I've tried using new and some other methods but I can't work through what I need to do. How can I fix this?
When I try to compile this code, I get the error "no match for 'operator[]' in 'myPointData.pointStruct::pointArray[4]' "
You should probably use std::vector like MadScienceDreams suggests.
However, if you want to learn about such things, you could use a pointer instead. For example:
struct pointStruct {
int numberPoints;
Point2D* pointArray;
};
void setPoints(void) {
pointStruct myPointData;
const int num_points = 4;
myPointData.numberPoints = num_points;
myPointData.pointArray = new Point2D[num_points];
for(int i = 0; i < num_points; ++i) {
myPointData.pointArray[i].x = ...;
myPointData.pointArray[i].y = ...;
}
// Do stuff with myPointData...
// Don't forget to have a "delete" for every "new" when you're done.
delete[] myPointData.pointArray;
}
Point2D pointArray;
pointArray is a single instance to Point2D. It is not an array of instances in which case it's type is Point2D [N].
myPointData.pointArray[4];
The above statement calls operator [] taking a parameter of type int, which is not you actually want. Since there is no such member function in Point2D, compiler complains. If you wish to create array of instances, use std::vector<Point2D>.
Related
As a C++ beginner, I oftentimes find myself struggling with the declaration of class attributes inside the header file that need more information than just a name, like arrays and objects of other classes with constructors.
Here's an example
SomeClass.h :
#include "OtherClass.h"
class SomeClass {
int num; // works fine
float arr[]; // produces an error because size is not declared
OtherClass obj; // produces an error because the constructor parameters are not passed in
public:
void setup();
void update();
};
SomeClass.cpp:
#include "SomeClass.h"
void SomeClass::setup() {
num = 10; // easy peasy, works!
arr = float some_arr[5 * num]; // error
// Fill in the array
for (int i = 0; i < 5 * num; i += num) {
ass[i] = 12;
}
// Fill in the class attributes
obj = {120, 40}; // error
}
void SomeClass::update() {
// Update stuff
}
In case of the array arr, how can I declare an array, if I don't know it's size at the moment of the declaration in the header file?
How can class objects with constructors be declared in the header file, without passing in unknown parameters at that moment?
Thanks.
In case of the array arr, how can I declare an array, if I don't know
it's size at the moment of the declaration in the header file?
You can't! C++ does not support variable length arrays, although some compilers (such as GCC) add support for them as an extension.
Instead, you should consider using the std::vector container type, from the Standard Template Library.
In your header/declaration:
class SomeClass {
int num; // works fine
// float arr[]; // produces an error because size is not declared
std::vector<float> arr;
//...
};
And, for your setup() function:
void SomeClass::setup() {
num = 10; // easy peasy, works!
// arr = float some_arr[5 * num]; // error
arr.resize(5 * num); // Sets the size of the container
// Fill in the array...
for (int i = 0; i < 5 * num; i += num) {
arr[i] = 12; // You can access (valid) elements just like a normal array!
}
//...
}
In case you don't know the array size before hand you can use dynamic allocation feature in C++.
First declare your array variable as follow
float *arr;
Then you can allocate required size as follows
arr=new float[10];
To deallocate memory
delete[] arr;
If want to dynamically allocate objects then,Declare class as
ClassName *obj;
Then to allocate use
obj=new ClassName(your_parameters);
Then you can delete it using
delete obj;
TIP:
It is always a good practice make pointer variable NULL after you have de-allocated memory.
Do arr=NULL; and obj=NULL; after de-allocating
I want to create a constant (preferably static but not necessary) member variable in my class.
I want it to be a 3-dimensional array with each length size 2.
The purpose: store some data that is time consuming to recreate on each change, for combinations of 3 types of boolean choices, without having to do complicated testing on each change.
What I don't know how to do: how to initialize the 3D array.
This is what I am trying (based on cplusplus.com/forum/Multi-Dimensional Arrays):
class MyClass {
public: ...
~MyClass(); // will I need to destroy m_previewIcons to prevent memory leak ?
private: ...
static const QIcon m_previewIcons[2][2][2]; // the array I need
static QIcon*** initializePreviewIcons(); // what type of return ?
};
const QIcon MyClass::m_previewIcons[2][2][2] = MyClass::initializePreviewIcons();
QIcon ***MyClass ::initializePreviewIcons()
{
QIcon ***iconArray = 0;
// Allocate memory
iconArray = new QIcon**[2];
for (int i = 0; i < 2; ++i)
{
iconArray[i] = new QIcon*[2];
for (int j = 0; j < 2; ++j)
iconArray[i][j] = new QIcon[2];
// is this even right ? it seems to me I miss out on a dimension ?
}
// Assign values
iconArray[0][0][0] = QIcon(":/image1.png");
iconArray[0][0][1] = QIcon(":/image2.png"); ...
iconArray[1][1][1] = QIcon(":/image8.png");
return iconArray;
}
As far as I got...
error: conversion from 'QIcon***' to non-scalar type 'QIcon' requested
How can I get this initialization to work ?
Note - QIcon is a built-in class in Qt, which is what I use (any class would be the same).
No C++ 11 though.
I could have used vectors I suppose but I wanted less overhead.
Edit: I have just thought of an alternate way to do it... give up on the 3D array, use simple 1D array and build an int for index using the booleans bit shifted. may be more effective.
But I would still want to know how to initialize a 3D array.
You're creating a a static array, and then trying to allocate its memory dynamically, which isn't necessary - the memory is already there by virtue of your declaration static const QIcon m_previewIcons[2][2][2];
You should initialize your 3d array using list initialization, a la this answer.
Heres an example with a non-POD type, std::string:
#include <string>
class MyClass {
public:
static const std::string m_previewIcons[2][2][2];
};
const std::string MyClass::m_previewIcons[2][2][2] = {
{ {":/image1.png",":/image2.png"},
{":/image3.png",":/image4.png"} },
{ {":/image5.png",":/image6.png"},
{":/image7.png",":/image8.png"} }
};
int main()
{
MyClass mc;
printf("%s\n", mc.m_previewIcons[0][0][0].c_str());
}
The problem is that C++ provides no class initialization: only static initializers or instance constructor.
But here, it is easy, because the construction of the elements of the array is straightforward, so you could use:
class MyClass {
public: ...
~MyClass(); // will I need to destroy m_previewIcons to prevent memory leak ?
private: ...
static const QIcon m_previewIcons[2][2][2]; // the array I need
};
const QIcon MyClass::m_previewIcons[2][2][2] = {
QIcon(":/image1.png"),
QIcon(":/image2.png"),
...,
QIcon(":/image8.png") };
As m_previewIcons has static linkage, its duration is the whole program so you have neither to provide storage for it nor to release it. Said differently, do not destroy it from the destructor.
I have written a function in c++ which receives a struct as a input. The struct object received has two arrays. I need to use both the arrays for different purposes. The array names have been created in a certain format. How to retrieve array names in a string.
struct INFO
{
float fADataLHS[3] = {1,2,3};
float fADataRHS[3] = {4,5,6};
Struct INFO has been defined where two arrays have been defined an initialized. The function useStruct uses both the function for different purposes.
void useStruct(struct *INFO)
{
--------;
--------;
}
int main()
{
struct INFO info;
useStruct(info);
}
I want a method in which I can retrieve the name of the array as for ex. fAdataLHS and store it to a string. The idea is to find the sub-string LHS and RHS from the string names and process then accordingly.
PS: I am quite new to c++.
I will go simple as you're a begginer to C++.
If you want to use both of arrays for different purposes, just doit. For instance:
void use_array_for_different_purposes(INFO *info)
{
// Purpose one, printing values using fADataLHS.
for (int i = 0; i < 3; i++) {cout << info->fADataLHS[i] << endl;}
// Purpose two, computing total sum using fADataRHS.
int acum;
for (int i = 0; i < 3; i++) {acum += info->fADataRHS[i];}
}
As you can see, you don't need to get the arrays names as strings values.
If I understand corectly, your use case is this: you have two (or more) names and each has a float array associated with it. You want to get the array by name and process the data.
Consider this code:
class INFO
{
std::map<std::string, std::vector<float>> vectors;
public:
INFO() : vectors{}
{
vectors["fADataLHS"] = { 1, 2, 3 };
vectors["fADataRHS"] = { 4, 5, 6 };
}
const std::vector<float>& operator[](const std::string& key) const // access vector by key
{
return vectors.at(key);
}
};
void useStruct(const INFO& info) // pass instance by const reference
{
std::cout << info["fADataLHS"][0] << "\n"; // access element 0 from the fADataLHS array
// get the entire array:
const auto& arr = info["fADataRHS"];
// this will throw a std::out_of_bounds
const auto& arr = info["non-existent-key"];
}
EDIT: A few other notes:
in C++ try not to use float - use double instead
if you need to alter the vector contents from client code, add a non-const version of the operator[]
C++ and Class
I have a class called “Sprite”, when this is initialized it takes a bool variable:
// constructor
Sprite::Sprite(bool type)
{
// set stuff
}
// two Sprites of different types
Sprite Hero(1)
Sprite Enemy(0)
Q. How do I initialize an array of 100 Sprites of type 0?
Sprite Enemies[100] ?
My suggestion is that you use a std::vector, and then use the constructor taking a value argument.
Like
std::vector<Sprite> Enemies(100, Sprite(false));
You might need proper copy-constructor and copy-assignment operators defined for Sprite for it to work.
If you don't have vectors (or std::array which might be better in your case), then you have to declare the array as a normal array, and then use a loop to initialize each entry:
Sprite Enemies[100];
for (size_t i = 0; i < 100; ++i)
Enemies[i].set(false);
You can use a default constructor, that will simply default to the 0 value like this:
//default constructor
Sprite::Sprite()
{
//set to false
}
Sprite::Sprite(bool type)
{
// set to type
}
Now
Sprite Enemies[100]
will work
Or with a little less code use a default value in the constructor like so:
Sprite::Sprite(bool type=false)
{
//set to type
{
Unless I'm wrong, you cannot directly use constructor with parameters for object arrays. One solution is using a std::vector :
std::vector<Sprite> Ennemies(100, Sprite(false));
std::vector<Sprite> Ennemies(100, {false}); // C++11 style
If you really want C-style array, you can get it, by an example :
Sprite* pEnnemies = &Ennemies.front();
One other solution is using the new C++11 container std::array which is only a C-Style array in STL syntax :
std::array<Sprite, 100> Ennemies(Sprite(false));
When creating an array of classes, they must be created by the default constructor.
You could add a default value "= false" for your type parameter, and then the code would work. It's not very flexible though, as you might want an array of the other type.
Another way is to allow your sprite to be reset after construction with a different type. After creating your array of blank sprites, call reset(type) on them in a for loop.
If you really need to use a non-default constructor on your elements, use std::vector. There are two ways to do it.
std::vector<Sprite> Enemies;
Enemies.reserve(100);
for (int i = 0; i < 100; i++)
{
Enemies.push_back(Sprite(0));
}
or
std::vector<Sprite> Enemies(100, Sprite(0));
For the sake of completeness, there is one last method using placement-new:
unsigned char data[sizeof(Sprite) * 100];
Sprite* ptr = reinterpret_cast<Sprite*>(&data[0]);
Sprite* end = ptr + 100;
for (; ptr != end; ++ptr)
new (ptr) Sprite(0);
This is pretty much what the other answers, that don't rely on the copy-constructor use internally.
If Sprite has a non-trivial destructor you will have to call it explicitly using another loop at the end of data's lifetime:
Sprite* ptr = reinterpret_cast<Sprite*>(&data[0]);
Sprite* end = ptr + 100;
for (; ptr != end; ++ptr)
ptr->~Sprite();
Many thanks all for taking a look, after reading comments I've found this works, overloading the constructor:
class Sprite
{
public:
Sprite();
Sprite(bool type);
void Move();
private:
unsigned int x, y, Ammo;
bool Alive;
bool Type;
};
// constructor
Sprite::Sprite()
{
Alive = true;
Type = 0;
Ammo = 25;
x = random(0, 82);
y = random(0, 20);
}
Sprite::Sprite(bool type)
{
Alive = true;
Type = 1;
Ammo = 25;
x = 20; // get x from btn press
y = 10; // get y from btn press
}
Sprite Hero(1);
Sprite Enemies[100];
Use a default argument:
Sprite::Sprite(bool type=false) : mymember(type)
{}
and then when you declare:
Sprite Enemies[100];
it will call the default ctor for all 100 elements.
You should learn about member-initializer lists, the proper way to write a constructor in C++ is:
Sprite(bool type=false); // declaration
...
Sprite::Sprite(bool type) : // definition
x(random(0, 82)),
y(random(0, 20)),
Ammo(25),
Alive(true),
Type(type)
{}
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.