I have really been struggling with a piece of code for a couple days. The error message i receive when i run my code is:
error: array initializer must be an initializer list
accountStore (int size = 0) : accts(size) { }
There seem to be others with similar problems here but unfortunately I am unable to apply their solutions (either don't work or not applicable).
What I am simply attempting to do is create a container class (array, can't use vectors) of a class 'prepaidAccount' but I am just unable to get the constructor portion of the container class 'storeAccount' to work. See code snippet below:
class prepaidAccount{
public:
//prepaidAccount ();
prepaidAccount(string newPhoneNum, float newAvailBal) : phoneNumber(newPhoneNum), availableBalance (newAvailBal){} //constructor
double addBalance(double howMuch) {
availableBalance = howMuch + availableBalance;
return availableBalance;
}
double payForCall(int callDuration, double tariff) {
callDuration = callDuration/60; //convert to minutes
double costOfCall = callDuration * tariff;
if (costOfCall > availableBalance) {
return -1;
}
else {
availableBalance = availableBalance - costOfCall;
return costOfCall;
}
}
void setAvailBal(int newAvailBal) {availableBalance = newAvailBal;}
float getAvailBal() {return availableBalance;}
void setPhoneNum(string newPhoneNum) {phoneNumber = newPhoneNum;}
string getPhoneNum() const {return phoneNumber;}
private:
string phoneNumber;
float availableBalance;
};
class accountStore { //made to store 100 prepaid accounts
public:
accountStore (int size = 0) : accts(size) { }
....
private:
prepaidAccount accts[100];
}
In main I simply call accountStore Account;
Any help is absolutely welcome. I very recently started learning c++ and about classes and constructors so please bear with me.
Thanks
You can't initialize an array with int like accountStore (int size = 0) : accts(size) {}.
prepaidAccount doesn't have a default constructor, you have to write member initialization list like,
accountStore (int size = 0) : accts{prepaidAccount(...), prepaidAccount(...), ...} { }
The array has 100 elements, it's not a practical solution here.
As a suggestion, think about std::vector, which has a constructor constructing with the spicified count of elements with specified value. Such as,
class accountStore {
public:
accountStore (int size = 0) : accts(size, prepaidAccount(...)) { }
....
private:
std::vector<prepaidAccount> accts;
};
Given that you have specified that you do not want to use a container such as std::vector but would like to specify the size at runtime, your only option would be to manually implement dynamic allocation yourself. Also given that you are wanting create 100 objects at a time, I would suggest making a function that can construct a temporary object according to your needs and then use this to initialise your dynamically allocated array. Consider the below code as a good starting point. (WARNING untested code.)
class prepaidAccount {
public:
// Constructor
prepaidAccount(string newPhoneNum, float newAvailBal)
: phoneNumber(newPhoneNum), availableBalance(newAvailBal) {}
// Default Constructor needed for dynamic allocation.
prepaidAccount() {}
/* your code*/
};
// Used to construct a tempoary prepaid account for copying to the array.
// Could use whatever constructor you see fit.
prepaidAccount MakePrepaidAccount(/*some parameters*/) {
/* Some code to generate account */
return some_var;
}
class accountStore {
public:
// Explicit constructor to avoid implicit type-casts.
explicit accountStore(const int &size = 0)
: accts(new prepaidAccount[size]) {
for (int i = 0; i < size; i++) {
// Will call defualt assignment function.
prepaidAccount[i] = MakePrepaidAccount(/*some parameters*/);
}
}
// Destructor
~accountStore() {
// Cleans up dynamically allocated memory.
delete[] prepaidAccount;
}
prepaidAccount *accts;
};
Edit: Amongst the c++ community it is often questionable when choosing to use dynamic allocation when there is such an excellent and comprehensive library of smart pointers. For example an std::vector would be perfect in this situation.
Related
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 a class like this:
class Wall
{
private :
Quad faces[6];
};
I have the constructor like this :
Wall::Wall(Quad f[], const float &mass, Vector3 center)
I want to initialize faces to be f(or copy f to faces),Quad is struct that doesn't have a default constructor.
Now I solved the problem by using faces{f[0],f[1],f[2],f[3],f[4],f[5]} in the initializer list but this requires c++11 which I'm afraid some of my friends don't have it, and I need to pass my code to them.
There are many similar questions but all of them seem to not have solutions other than switching to vector or using some complicated code which I don't want, as you can understand from the classes' name, a Wall doesn't need a vector(it only has 6 faces so why a vector).
Is this really hopeless ? isn't there any way ?
PS
Whether in the constructor body or in the initializer list, it doesn't matter.
changing to dynamic arrays(Quad *) doesn't matter either but keeping with static arrays is preferable.
Several options. The easiest is probably to subclass Quad with something that has a default constructor:
class Wall {
public:
Wall(Quad f[], ...) {
for (int i = 0; i < 6; ++i) faces[i] = f[i];
}
private:
class MyQuad : public Quad {
MyQuad() : Quad(...) {}
}
MyQuad faces[6];
};
Another option is to use placement new - note that the code below doesn't work out of the box since it is not doing proper alignment/padding and dealing with some aliasing issues, which are left as an exercise to the reader. It should give you a starting point though.
class Wall {
public:
Wall(Quad f[], ...) {
for (int i = 0; i < 6; i++) {
// TODO: take padding into account
new (&faces_data + sizeof(Quad) * i) Quad(f[i]);
}
}
~Wall() {
for (int i = 0; i < 6; i++) {
face(i).~Quad();
}
}
Quad& face(int idx) {
// TODO: take padding into account
return (reinterpret_cast<Quad*>(faces_data))[idx];
}
private:
// TODO: force proper alignment and take padding into account
char faces_data[sizeof(Quad) * 6];
};
I have 1 question because I am pretty curious how to handle with such problem.
I have base class called "Pracownik" (Worker) and 2 subclasses which are made from public Pracownik;
- Informatyk (Informatic)
- Księgowy (Accountant)
Writing classes is easy. Made them pretty fast but I have small problem with main because I am helping friend with program but I was not using C++ for a while. So:
This is my header file "funkcje.h"
#include <iostream>
using namespace std;
class Pracownik
{
private:
string nazwisko;
int pensja;
public:
Pracownik(string="",int=0);
~Pracownik();
string getNazwisko();
int getPensja();
friend double srednia_pensja(int,Pracownik);
};
class Informatyk : public Pracownik
{
private:
string certyfikat_Cisco;
string certyfikat_Microsoft;
public:
Informatyk(string="",int=0, string="", string="");
~Informatyk();
void info();
};
class Ksiegowy : public Pracownik
{
private:
bool audytor;
public:
Ksiegowy(string="",int=0, bool=false);
~Ksiegowy();
void info();
};
double srednia_pensja(int,Pracownik);
These are definitions of my functions "funkcje.cpp"
#include "funkcje.h"
Pracownik::Pracownik(string a,int b)
{
nazwisko=a;
pensja=b;
}
Pracownik::~Pracownik()
{
}
string Pracownik::getNazwisko()
{
return nazwisko;
}
int Pracownik::getPensja()
{
return pensja;
}
Informatyk::Informatyk(string a, int b, string c, string d) : Pracownik(a,b)
{
certyfikat_Cisco=c;
certyfikat_Microsoft=d;
}
Informatyk::~Informatyk()
{
}
Ksiegowy::Ksiegowy(string a, int b, bool c) : Pracownik(a,b)
{
audytor=c;
}
Ksiegowy::~Ksiegowy()
{
}
void Informatyk::info()
{
cout<<"Nazwisko pracownika: "<<Pracownik::getNazwisko()<<endl;
cout<<"Pensja pracownika: "<<Pracownik::getPensja()<<endl;
cout<<"Certyfikat Cisco: "<<certyfikat_Cisco<<endl;
cout<<"Certyfikat Microsoft: "<<certyfikat_Microsoft<<endl;
}
void Ksiegowy::info()
{
cout<<"Nazwisko pracownika: "<<Pracownik::getNazwisko()<<endl;
cout<<"Pensja pracownika: "<<Pracownik::getPensja()<<endl;
cout<<"Audytor: ";
if(audytor)
cout<<"Tak"<<endl;
else
cout<<"Nie"<<endl;
}
double srednia_pensja(int a,Pracownik *b)
{
return 0;
}
And finally main!
#include <iostream>
#include "funkcje.h"
using namespace std;
int main()
{
Pracownik lista[10];
Pracownik *lista_wsk = new Pracownik[10];
Informatyk a("Kowalski1",1000,"Cisco1","Microsoft1");
Informatyk b("Kowalski2",2000,"Cisco2","Microsoft2");
Informatyk c("Kowalski3",3000,"Cisco3","Microsoft3");
Ksiegowy d("Kowalski4",4000,1);
Ksiegowy e("Kowalski5",5000,0);
lista[0]=a;
lista[1]=b;
lista[2]=c;
lista[3]=d;
lista[4]=e;
Informatyk *ab = new Informatyk("Kowalski1",1000,"Cisco1","Microsoft1");
Informatyk *ac = new Informatyk("Kowalski2",2000,"Cisco2","Microsoft2");
Informatyk *ad = new Informatyk("Kowalski3",3000,"Cisco3","Microsoft3");
Ksiegowy *ae = new Ksiegowy("Kowalski4",3000,1);
Ksiegowy *af = new Ksiegowy("Kowalski5",3000,0);
lista_wsk[0]=*ab;
lista_wsk[1]=*ac;
lista_wsk[2]=*ad;
lista_wsk[3]=*ae;
lista_wsk[4]=*af;
for(int i;i<5;i++)
{
lista[i].info();
cout<<endl;
}
cout<<endl;
// for(int i;i<5;i++)
// {
// lista_wsk[i].info();
// }
return 0;
}
Ok and here goes my questions:
I had to create array which is filled with base class objects "Pracownik".
Secondary i had to create array which is full of pointers to class "Pracownik" objects.
(Hope those 2 first steps are done correctly)
Next thing I had to write to array 3 objects of class Informatic and 2 of class Accountant.
So I ve created 5 objects manually and added them into the array in such way array[0]=a;. I guess this is still good.
Next thing i had to create and add similar objects to array of pointers using new. So I ve created array with new and pointers to objects with new. (Hope thats correct 2).
And FINALLY:
I had to use info() on added to array objects.
This is my main question if my array is type "Pracownik" and I want to use function info() from subclasses how should I do that? And how compiler will know if he should use info() from Accountant or Informatic while I am trying to show those information using "for".
In an array of Pracownik, the elements are of type Pracownik. Any information about the objects being of a subclass of Pracownik are lost when you copy the elements into the array.
This is called object slicing and leads to the fact that there is no way to invoke Informatyk::info() on these objects.
If you want to call methods of a subclass, you have to prevent object slicing by storing pointers or references in the array.
As Oswald says in his answer,
Pracownik * lista_wsk = new Pracownik[10];
allocates an array of 10 Pracownik objects. This is probably not what you want. With polymorphism involved, we usually want to deal with pointers or references. Hence, you'd want an array of Pracownik * pointers. Since you already know at compile-time that it will have 10 members, there is no need for a dynamic allocation here. I think you've meant to write
Pracownik * lista_wsk[10];
instead. Now we don't put objects but pointers to objects into the array. For example:
lista_wsk[2] = new Informatyk("Kowalski3", 3000, "Cisco3", "Microsoft3");
And then we can iterate over the items like so:
for (unsigned i = 0; i < 10; ++i)
std::cout << lista_wsk[i]->getNazwisko() << std::endl;
As you have already discovered, it is impossible to call a subclass function member on a superclass object. It would be possible to figure out the actual type at run-time yourslf by means of a cast.
for (unsigned i = 0; i < 10; ++i)
if (Informatyk * info_ptr = dynamic_cast<Informatyk *>(lista_wsk[i]))
info_ptr->info();
dynamic_cast returns a pointer to the target class if this is possible or a nullptr (which evaluates to false, hence the conditional) otherwise. Note however that this is considered very poor style. It is better to use virtual functions. Therefore, add
virtual void
info()
{
// Do what is appropriate to do for a plain Pracownik.
// Maybe leave this function empty.
}
to the superclass and again to the subclass
virtual void
info() // override
{
// Do what is appropriate to do for an Informatyk.
}
The function in the subclass with the same signature is said to override the function inherited from the superclass. Since the function is marked as virtual, the compiler will generate additional code to figure out at run-time what version of the function to call.
If you are coding C++11, you can make the override explicit by placing the keyword override after its type as shown above (uncomment the override). I recommend you use this to avoid bugs that arise from accidental misspelling or other typos.
Say I have a class:
class A
{
private:
const int * const v;
public:
A();
}
I want v to be allocated in the initialization list, and I think I can define the following constructor:
A::A():v((int*)malloc(10*sizeof(int))){}
However, what about v has to be allocated in a non-standard way like the following:
cudaMalloc(&v,10*sizeof(int));
Note cudaMalloc is a CUDA API to allocate GPU memory.
(Ignoring the bigger-picture matters of overall design, exception safety etc. and focusing on the question in its most narrow scope)
Abandon the idea of doing in the initializer list and do it in the constructor body instead
A::A() : v(NULL)
{
cudaMalloc(&v, 10 * sizeof(int));
}
Or, alternatively, wrap the allocation function into your own function that returns the pointer
void *wrapped_cudaMalloc(size_t size)
{
void *m = NULL;
cudaMalloc(&m, size);
return m;
}
...
A::A() : v(wrapped_cudaMalloc(10 * sizeof(int)))
{}
Just for the sake of completeness, there's also an ugly convoluted way to do it in the initializer list without creating any wrappers by exploiting the properties of , operator
A::A() : v((cudaMalloc(&v, 10 * sizeof(int)), v))
{}
Note the additional pair of () around the comma-expression, which is needed to satisfy the initialization syntax (otherwise , will be treated as argument separator instead of comma operator).
In addition to AndreyT's excellent post (and his creative use of the comma operator), you could also wrap things up thusly:
class cudaMallocedInt
{
private:
int *v;
public:
cudaMallocedInt(int n)
{
cudaMalloc(&v, n * sizeof(int));
}
cudaMallocedInt(const cudaMallocedInt &o)
{
// Do whatever is appropriate here. Probably some sort of dance.
}
~cudaMallocedInt()
{
// Remember to cudaFree or whatever
}
operator int*()
{
return v;
}
};
class A
{
private:
cudaMallocedInt v;
public:
A()
: v(10)
{
}
...
};
Update: As Johnsyweb pointed out in comments, please be sure to adhere to the Rule of Three to make sure things don't go boom and you waste your weekends tracking down hard to debug errors instead of having fun!
Alright, wasn't quite sure how to word the question and couldn't find any duplicates that I think really address this situation.
Essentially I have a super class that gets extra data appended to it through a subclass. The container class for this data recognizes only the super class and adjust characteristics based on an id parameter in the super class.
I've actually never had to used inheritance in c++ till recently so forgive me if this is trivial. I'm under the impression that when I go to hard copy a bunch of data using the superclass, the subclass data is loss in translation so to speak. In order to bypass this limitation I'm trying to use a typecast-ed pointer however I now get a segmentation fault when trying to free the memory even when typecasting the pointer parameter in the free() function.
Here is the sample code...
Structs
// Super class
struct Vertex {
__declspec(align(4)) unsigned int vType; // Identifies the vertex type.
Vertex(const unsigned int _vType) : vType(_vType) { }
Vertex(const Vertex &_rV) : vType(_rV.vType) { } // Copy constructor
virtual ~Vertex() { }
unsigned int GetVType() const { return vType; }
};
// Subclass
// Id = 1
struct V_Pos : Vertex {
__declspec(align(4)) XMFLOAT3 position;
V_Pos(void) : Vertex(1) { }
V_Pos(XMFLOAT3 &_rPosition) : Vertex(1), position(_rPosition) { }
V_Pos(const V_Pos &_rV) : Vertex(_rV), position(_rV.GetPosition()) { } // Copy constructor
~V_Pos() { }
XMFLOAT3 GetPosition() const { return position; }
};
Here is how I'm currently copying the data.
// pBuffer is declared as a Vertex* data type
pBuffer = new V_Pos[_bufSize];
if (_pVBuffer->GetVType() == 1)
for (unsigned int i = 0; i < bufSize; ++i) {
V_Pos *_temp = (V_Pos*)&_pVBuffer[i];
pBuffer[i] = *_temp;
}
Here is how I am currently de-allocating the data.
if (pBuffer != 0) {
delete [] pBuffer;
pBuffer = 0;
}
What is the correct approach for this situation?
Edit 1 -
Updated the above code blocks to clarify the comment discussion under knulp's answer.
If you start mixing low level memory allocation with malloc()/free(), and C++ objects, you will run into a lot of troubles, while making your code almost unreadable.
You should create a new object with new on a proper constructor, which automatically 1) allocates memory and 2) initializes the struct. To properly free the memory you should use delete and the destructor.
You should copy using a copy constructor and an assignment operator. If you do not define them, the default ones are automatically defined by the compiler to perform a bitwise copy.
Why are you using a type field? C++ has a very strong typing features, so it makes very little sense to bypass all C++ mechanism to define a vType. Rather, define a base class, and two or more derived classes from there, and just eliminate the vtype field.
If you use clean OO programming, you will avoid all these problems from the start.
Your base class needs to have a virtual destructor. This will allow you to safely delete a derived class with a base class pointer.
Not that! Use a copy constructor.
// Super class
struct Vertex {
__declspec(align(4)) unsigned int vType; // Identifies the vertex type.
Vertex(const unsigned int _vType) : vType(_vType) { }
unsigned int GetVType() const { return vType; }
Vertex(const Vertex& v) : vType(v.vType) {}
};
// Subclass
// Id = 1
struct V_Pos : Vertex {
__declspec(align(4)) XMFLOAT3 position;
V_Pos(void) : Vertex(1) { }
V_Pos(XMFLOAT3 &_rPosition) : Vertex(1), position(_rPosition) { }
V_Pos(const V_Pos& v) : Vertex(v) {
position[0] = v.position[0];
position[1] = v.position[1];
position[2] = v.position[2];
}
};
Better yet, use a vecotr instead of XMFLOAT3;
Create a copy on the heap:
V_Pos original(...);
V_Pos * copyPtr = new V_Pos(original);