Let's say in a class a constructor is overloaded. Can multiple data members be initialized for the single object using different constructors of the same class?
eg :
class demo{
int size;
double k;
public:
demo(int s){
size=s;
}
demo(double p){
k = size+p;
}
void show(){
cout<<size<<" "<<k<<"\n";
}
};
int main(){
demo a = demo(0);
a = 4.7;
a.show();
return 0;
}
Is this possible?
No, once the object is constructed, it's constructed.
Let's go through your code and see what it does (assuming no optimizations, please note that many modern compilers will do some copy-elision even in debug or -O0 modes):
demo(0);
The code demo(0) calls the demo(int s) constructor. A temporary rvalue is created. So now we have a temporary object with the values:
size = 0
k = uninitialized
demo a = demo(0);
demo a is then created using an implicit copy constructor.
We now have a demo object named a with the following values:
size = 0
k = uninitialized
a = 4.7;
Because a is already constructed, this will call an implicit assignment-operator. The default assignment-operator will copy all the values from one object into the other object. This means the 4.7 needs to be converted into a demo object first. This is possible because of your demo(double p) constructor.
So a temporary demo object will be created with the values:
size = uninitialized
k = uninitialized + 4.7 = undefined
These values will be copied into a and so both of a's data members will be undefined.
Possible Solutions
songyuanyao's solution of using a constructor with multiple parameters is one good way of doing it.
Using setters is another way.
Either way, I would recommend having your constructors provide default values for your data-members.
demo(int s)
{
size = s;
k = 0.0; // or some other suitable value
}
Here's how you could create a setter.
void setK (double p)
{
k = size + p;
}
You could then do this:
int main ()
{
demo a (0) ;
a.setK (4.7) ;
a.show () ;
return 0 ;
}
I think you're after the Builder Pattern.
You should define a ctor which can take multiple parameters to initialize multiple data members:
demo(int s, double p) {
size = s;
k = size + p;
}
and then
int main() {
demo a(0, 4.7);
a.show();
return 0;
}
Related
As the example below, I define 2 variables x and y. When I call the lambda function twice, it seems like it will not destroy the copy. From 11.14 — Lambda captures | Learn C++ - Learn C++, it says:
Because captured variables are members of the lambda object, their values are persisted across multiple calls to the lambda!
How does C++ manage the memory for lambda function?
int main() {
int x = 1;
static int y = 1;
auto fun = [=]() mutable{
x++;
y++;
cout<<"Inside:\t\t";
cout<<"x:"<<x<<"\t"<<"y:"<<y<<endl;
};
for (int i = 0; i<2; i++) {
fun();
cout<<"Outside:\t";
cout<<"x:"<<x<<"\t"<<"y:"<<y<<endl<<endl;
}
}
Output:
Inside: x:2 y:2
Outside: x:1 y:2
Inside: x:3 y:3
Outside: x:1 y:3
It stores it inside the object itself. Another way to think of your lambda is below. This is "kind of" equivalent to what the compiler is generating, and yes, I'm changing scopes around a bit and I know that, but this may be clearer to a beginner at C++.
static int y = 1; // Moved this out from main
class my_lambda{
public:
my_lambda(int x) : _x(x) {}
~my_lambda() = default;
void operator()()
{
_x++;
y++;
cout<<"Inside:\t\t";
cout<<"_x:"<<_x<<"\t"<<"y:"<<y<<endl;
}
private:
int _x;
};
int main() {
int x = 1;
my_lambda fun{x}; // "Captures" x
for (int i = 0; i<2; i++) {
fun();
cout<<"Outside:\t";
cout<<"x:"<<x<<"\t"<<"y:"<<y<<endl<<endl;
}
}
As you can hopefully see, the "fake lambda" class I made is doing the same thing your actual lambda is. It "captures" x as part of its constructor and copies it to internal storage, which I called _x. And y is just in scope for it, though I moved to global to be above the class declaration.
I'm overloading the () operator to make a class that's callable, which is a normal thing to do in some circumstances. See operator overloading if you wish for more information.
So this is "kind of, sorta" how lambdas work. They take your body and put it into the operator() of the object that's generated, and anything captured is one of the object's variables, with either the actual object (if by value) or a reference, if captured that way.
And to directly answer your question: when fun goes out of scope, it is freed, both in a lambda, and my case.
#include<iostream>
using namespace std;
template<class T>
class vee
{
T* v;
int size;
public:
vee(int m)
{
v = new T[size=m];
cout<<size<<"\n";
}
vee(T* a)
{
cout<<size<<"\n";
for(int i=0;i<size;i++)
{
v[i]=a[i];
}
}
};
int main()
{
int x[]={1,2,3};
int y[]={2,3,4};
vee<int> v1(3);
v1=x;
return 0;
}
Why i am getting 2 different values of "size" ?
I have created a constructor to intilize the parameter size and it shows correct value in first constructor but it throws a garbage value in the second constructor ,why??
Why i am getting 2 different values of "size" ?
vee(T* a) is called converting constructor. When you write something like v1=x;, array x decays to a pointer, then it is converted to vee with provided converting constructor.
v1=x; is as if you wrote v1=vee<int>(x);
As you can see a temporary instance is created with undefined size and pointer, which is bad. Then you assign this instance to v1 which is worse.
If you do not want this autoconversion in the future, declare your constructor explicit
explicit vee(T* a)
When doing v1=x, you actually go and create new object, since you have not overrided the '=' operator.
but it throws a garbage value in the second constructor ,why??
vee(int m)
{
v = new T[size=m]; // in this constructor you set size
cout<<size<<"\n";
}
vee(T* a)
{
// but in this constructor you don't set size
cout<<size<<"\n";
for(int i=0;i<size;i++)
{
v[i]=a[i];
}
}
So, when you create a vee using the second constructor - and read from size - your program has undefined behaviour.
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.
class A
{
public:
A() {}
A(int _x) : x(_x) {}
private:
int x;
};
int main()
{
A a[100](1); //compile error
A ptr = new A[100](1); // compile error
return 0;
}
As we know, the sample code will encounter compile error, because an object array can be initialized only by default constructor.
Why cannot an object be initialized using a constructor with parameter?
I recently read the book Inside the C++ Object Model. As the book mentioned, when initializing an object array, the process will call a function (named vec_new in cfront 2.0) which accepts a constructor pointer and call the constructor without any arguments. It means the function can only call the default constructor, so an object array can be initialized only using the default constructor.
But, why does the compiler use vec_new to initialize an object array?
If the compiler does not call the vec_new, it can expand the code to initialize all the objects in an array like the sample code:
int main()
{
A ptr = new A[100](1);
////// expanded code, I suppose
/** 1. allocate memory to ptr
* 2. constuct 100 object respectively
* int i = 0;
* char *tmp_ptr = (char *)ptr;
* while(i++ < 100) {
* tmp_ptr = A::A(tmp_ptr, 1);
tmp_ptr += sizeof(A);
}
*/
return 0;
}
I confuse that if a compiler implement "initializing an object array using constructor with arguments"?
I want to do something like this:
int displayAll(Message *m, string &lastIndex, int &NumPrinted = 0 );
It gives me error, cribbing about int to int&.
I tried this too:
int temp =0;
int displayAll(Message *m, string &lastIndex, int &NumPrinted = temp );
Still it gives following error:
error: ISO C++ forbids in-class initialization of non-const static member 'temp'
Even static int temp; gives error.
error: ISO C++ forbids in-class initialization of non-const static member 'temp'
The problem with the first line of code you mention is that you are trying to pass a reference to a temporary variable
class Foo {
int displayAll(Message *m, bool &moreElements, string &lastIndex, int &NumPrinted = 0 );
};
The second bit of code complains because you were trying to initialize a class member statically.
class Foo {
int temp =0;
int displayAll(Message *m, bool &moreElements, string &lastIndex, int &NumPrinted = temp );
};
(I am putting your code inside of a class declaration to be clear about what is happening).
An easy way out of your problem that does not introduce a static variable is explicit function overloading:
class Foo {
inline int displayAll(Message *m, bool &moreElements, string &lastIndex) {
int dummy = 0;
return displayAll(m, moreElements, lastIndex, dummy);
}
int displayAll(Message *m, bool &moreElements, string &lastIndex, int &NumPrinted);
};
There's a bit of boilerplate, but it achieves what you want.
Hope this helps.
EDIT: Some more clarification. The core of the problem stems from the fact that the function must take a reference to some memory that it can modify. If you pass it a temporary variable (temporary as in the C++ meaning of the term, not just the english language term ) (as in your first line of code), it's illegal C++, since you usually copy a temporary to a value before you use it as an argument to a function:
void bar( int someNum = 0 ); // think of this as creating a temporary rvalue 0
// and then copying it into the function for use.
// temporary rvalues arise in expressions like
int v = 5 + 5; // the result of 5 + 5 is stored in a temporary rvalue, and then
// copied into v (which is an lvalue in this case).
So we need something that is an "lvalue", either some global variable somewhere or a temporary local variable ( in the english language sense ) as I gave in my answer. I was about to write a solution using a static variable, but there is a large flaw- since the static variable will be shared by all instances of your class, it will start out 0 and then be different every time you call the method ( since it would have been edted by the previous call). Even worse, in the case of multiple threads, you would be reading/writing to the same place of memory from several processors, so the value will be complete garbage, and you ill rape your processor cores' caches as each write will invalidate the cache of every other core. It's ugly, please don't do it. :P
By using my first solution you make the temporary variable very local, without much impact on anything else.
You can't do this for a non-const reference unless you declare temp to be static: see this stackoverflow post.
I fpund this interesting way of achieving this too:
class demo {
public:
void displayAll(int &x, int y = 0 ) {
int *p;
if(y)
p = (int*)y;
if(p) *p = 10;
x = 4;
}
};
int main() {
int x=0, y=0;
demo *obj = new demo();
obj->displayAll((x);
//obj->temp(x,(int)&y);
cout << "\n x= " << x << " y " << y;
return 0;
}