C++ Array initialization - c++

the code below gives compilation error when I try to create test t[2];
because there is no default constructor for this.
But if I create Test t[2] = {test(1,2), test(2,3)}; Then it works fine.
1)But think of a situation, if we want to create more then 100 array element. We need to create 100 element in the curly braces like..
Test t[100] = {test(1,2), test(1,2)……/100 times/};
The above code is difficult to maintain.
One more solution is to create public member function which takes 2 integers and run in a loop. This solves the problem but i want to know any other good method.
2) If I create it using new
Test *t = new test[10];
I get compilation error(No default constructor). How to solve this.
class test
{
int _a;int _b;
public:
test(int a, int b);
void display();
};
int _tmain(int argc, _TCHAR* argv[])
{
test t[10];
for (int i = 0 ; i< 10; i++)
t[i].display();
}

In order to construct your 10 elements in the array the compiler somehow has to instaciate them through a constructor. For arrays only a default constructor (taking no arguments) can bes used, as you can not pass any arguments to the elements in the array. Therfor you have to proved a constructor
test::test()
taking no arguments.

In your example what do you expect to be displayed?
If you know that, you can write a Default CTor (one that has no parameters) and set your values to the defaults.
An example of the Default CTor:
// Variant 1: Use the initialization list
test()
: a(-1)
, b(-1)
{
}
// OR
// Variant 2: Do it in the CTor's body
test()
{
a = -1;
b = -1;
}
Note: You can write several CTors (it's called "overloading"). One that takes no parameters and sets default values and others that take parameters and set those values.

You can also define a constructor with default values for all parameters which will be used as the default constructor.
test(int a = 0, int b = 0) :_a(a), _b(b) {}
Since all parameters have default values, this constructor will be used as the default. Leaving out the initialization list or not initializing the member variables in the body of the constructor may give you random data values. Some systems may zero all memory allocations, but some do not.

Related

Is it possible to pass arguments to std::make_unique() when allocating an array?

In the code below, is there any way that I can pass an argument to the demo constructor when using std::make_unique() to allocate a demo[] array?
class demo{
public:
int info;
demo():info(-99){} // default value
demo(int info): info(info){}
};
int main(){
// ok below code creates default constructor, totally fine, no problem
std::unique_ptr<demo> pt1 = std::make_unique<demo>();
// and this line creates argument constructor, totally fine, no problem
std::unique_ptr<demo> pt2 = std::make_unique<demo>(1800);
// But now, look at this below line
// it creates 5 object of demo class with default constructor
std::unique_ptr<demo[]> pt3 = std::make_unique<demo[]>(5);
// but I need here to pass second constructor argument, something like this : -
//std::unique_ptr<demo[]> pt3 = std::make_unique<demo[]>(5, 200);
return 0;
}
std:::make_unique<T[]>() does not support passing arguments to the constructor of array elements. It always invokes the default constructor only. You would have to construct the array manually, eg:
std::unique_ptr<demo[]> pt3(new demo[5]{200,200,200,200,200});
Which is obviously not going to be useful if you have a large number of elements to create. You could do something like this instead, if you don't mind re-initializing them after constructing them:
std::unique_ptr<demo[]> pt3 = std::make_unique<demo[]>(5);
std::fill_n(pt3.get(), 5, 200);
Otherwise, just use std::vector instead:
std::vector<demo> pt3(5, 200);

Constructor of class of an array

i am getting error in this code
class business
{
public:
business(); // Default Constructor
business(string busines,int r)
{
busines=busines;
ratings=r;
} // constructor;
private:
string busines;
int ratings;
int items_owned;
int business_cancellation;
int biz_size_of_building;
int biz_shipping_method;
};
int main(int argc, char *argv[])
{
business b[10];
b[b_count](busines,rating);
return 0;
}
It gives me the following error (http://ideone.com/FfajNS):
prog.cpp: In function ‘int main(int, char**)’:
prog.cpp:32:32: error: no match for call to ‘(business) (std::string&, int&)’
You're attempting to call a constructor on an already constructed object ... the default constructor was called during the array creation, therefore you cannot "construct" the object again. For your application, you may want to look into using a std::vector where you can create a array-like container using an object initialized from a set of default arguments.
For instance, you could do:
std::vector<business> array(10, business(business_string, rating));
I believe you want something like this:
b[2] = business("Denny's", 50);
This creates a temporary business variable by calling the constructor with the given parameters. The temporary is then copied into slot 3 of the array b.
The array b already created 10 business objects using the default constructor of that class. You can access those objects by business someBusiness = b[someIndex];
edit:
If you want to set the values of your individual objects, simply do this (notice, that you don't create these objects, just set their values):
for(int i=0; i<10; i++)
{
b[i].busines = ...;
b[i].ratings = ...;
/* or to create new ones */
b[i] = business("asd", 10);
}
It would be even better, if you stored these objects in vector, like Jason suggested
business b[10];
You create 10 "default" business object. What is b_count? I hope some int from 0 to 9.
But here you are "calling" a business object with 2 arguments:
b[b_count](busines,rating);
But business have no operator()() defined with 2 parametr.
EDIT:
You definitely have to use std::vector and carefully read the other answers.
But I know that on occasion beginners are not allowed to use the STL library, and anyway it seems that you should understand how constructors are used and how the elements of an array are initialized. Please read about static members and how they are defined and try to understand how the following example works.
#include <string>
using std::string;
class business
{
public:
business() // Default Constructor
:busines(def_busines),ratings(def_ratings){};
business(const string& bus,int r) // constructor;
:busines(bus),ratings(r){}
static void SetDef(const string& busines,int r)
{
def_busines=busines;
def_ratings=r;
}
private:
string busines;
int ratings;
static string def_busines;
static int def_ratings;
int items_owned;
int business_cancellation;
int biz_size_of_building;
int biz_shipping_method;
};
string business::def_busines=""; // Set here the default-defaults
int business::def_ratings=1;
int main(int argc, char *argv[])
{
business::SetDef("Some business",2);
business a[10];
business::SetDef("Other business",3);
business b[10];
business c("Third business",4);
return 0;
}

C Programming, Variables

When we declare variables in a class and then when we assign the value of those variables, for example like this
class c {
public :
int x;
int x2;
c () {
x = 0;
x2 = 0;
scanf ("%d", &x); and now we're gonna input for example 10
}
};
each time the class is used, I mean each time the constructor is called, the value of x becomes 0 again since it is initialized as zero in the constructor. However if we don't initialize the value, there will be errors.
My question is that how can we keep the value of the variable when we call the constructor again and again so that it doesn't become zero ?
Edit:
void example () {
int i;
scanf ("%d", &i);
switch (i) {
case 1 : {Object ob1; system ("cls"); menu ();} // this object contains a value like 20
case 2 : {Object ob2; system ("cls"); menu ();}
}
}
There is another switch case in Object 1 which includes an option to go back to a main menu, now if I enter 1 again go back to object 1 I cannot see the value 20, it will be 0
The constructor is called only once for each instance so need to worry about that. You will never reset the value of x for a given instance to 0 because of its constructor.
Do you understand the difference between classes and objects/instances? Classes are merely a "Cookie-cutter" for objects. You don't "call" a constructor as such, but you create an instance of your class (which implicitely calls the constructor):
c myObj;
c anotherObj;
This code will create two instances of class c, both with their own version of x1 and x2. It's true that the constructor is run a second time when creating anotherObj, but it operates on totally different memory. So the values of x1 and x2 in myObj won't be touched.
Edit: The point of class member functions is that they operate on an implicit additional parameter named this. You could imagine that the "constructor call" actually looks like that (Just for illustrative purposes, not meant to be valid code):
c* this = malloc(sizeof(c));
constructor(c);
// With "constructor" actually being:
void ctor(c* this) {
this->x1 = 0;
this->x2 = 0;
// ..
}
That can also be achieved in C - but in C++, it happens implicitly, without you having to write code like this. You just write c newObj; or c* obj = new c;.
Apart from that: Member variables should be privat, and your mixing C library code (scanf) with C++ classes - use iostreams for input/output in C++.
You can store it in a static variable. Then read the value of x from that static variable.

Initialization of vector in a constructor - C++

I'm struggling with the constructor of one of my classes do to a member
that is not initialized properly.
I have a class "Settings" that handles the setting I use for my simulations
and a class Simulations that performs the simulation steps.
What I can't understand is why this code doesn't work as expected:
class Settings{
public:
int n ; // a number I need to create properly a vector in my class simulation
// ... rest of the code constructors etc to read values from files.
// everything works fine and the values are assigned properly
}
class Simulation{
public:
std::vector<int> v ;
Settings *SP;
Simulation(Settings *);
}
Simulation::Simulation(Settings *pS)
:SP(pS), v(std::vector<int>(SP->n,0)) {} // the constructor doesn't work,
// v is initialized but it is not created as a vector of size n, but 0.
I think there is a problem in the way I use the constructor but I can't understand why.
By the way defining v inside the curly brackets works fine, I'm just curious to know why
defining it the proper way doesn't work as expected!
Thanks a lot for the help!
You don't need the extra vector:
Simulation::Simulation(Settings *pS)
:SP(pS), v(SP->n,0) {}
If this doesn't work, this isn't your code. Are you sure SP is declared before v in the class definition? If this also doesn't work, try with pS instead of SP.
You've verified that pS->n != 0 prior to instantiating the Simulation, right?
Anyway, I think the line you're looking for in your constructor is:
:SP(pS), v(pS->n, 0) {}
The way you're doing it now is creating a whole std::vector and then copying it to v.
Also please make sure you check SP is not null pointer. This will otherwise have a crash.
Simulation::Simulation(Settings *pS)
:SP(pS), v(pS != NULL ? pS->n : 0 , 0) {}
This will check for SP not being NULL. this is the case when Simulation(NULL) is used as constructor.
You don't need to create an extra vector and use the copy constructor. Just pass the arguments straight to your vector in the member initializer. As another poster mentioned, did you verify that the return of SP->n is actually not 0? If you hardcode some values in, you'll see that it works fine, as below:
#include <iostream>
#include <vector>
using namespace std;
class foo
{
public:
foo();
vector<int> vec;
};
int main()
{
foo obj;
for(int i=0;i<obj.vec.size();++i) {
cout << obj.vec[i] << ' ';
}
system("pause");
return 0;
}
foo::foo()
:vec(vector<int>(10,2))
{
}

Calling overloaded constructor from constructor initialisation list

In the code below, my intent is to call one of two overloaded constructors for the kap (class opacity) based on what arguments are passed to the object of class material:
class opacity{
private:
int mode;
double kap_const;
double kappa_array[10][10];
public:
opacity(double constkap); // picking the constructor sets the mode
opacity(char* Datafile);
double value(double T, double P); // will return a constant or interpolate
};
opacity::opacity(double constkap):mode(1){
kap_const = constkap;
}
opacity::opacity(char* Datafile):mode(2){
// read file into kappa_array...
}
class Matter {
public:
Matter(int i, double k, char* filename); // many more values are actually passed
opacity kap;
int x; // dummy thing
// more variables, call some functions
};
Matter::Matter(int i, double k, char * filename)
:x(k>0? this->kap(x): this->kap(filename) ) {
// ... rest of initialisation
}
This is however not working:
test.cpp: In constructor 'Matter::Matter(int, double, char*)':
test.cpp:32:21: error: no match for call to '(opacity) (void*&)'
test.cpp:32:42: error: no match for call to '(opacity) (char*&)'
test.cpp:32:44: error: no matching function for call to 'opacity::opacity()'
test.cpp:32:44: note: candidates are:
test.cpp:20:1: note: opacity::opacity(char*)
test.cpp:20:1: note: candidate expects 1 argument, 0 provided
test.cpp:16:1: note: opacity::opacity(double)
test.cpp:16:1: note: candidate expects 1 argument, 0 provided
test.cpp:4:7: note: opacity::opacity(const opacity&)
test.cpp:4:7: note: candidate expects 1 argument, 0 provided
The first thing I had tried,
Matter::Matter(int i, double k, char * filename)
:kap(k>0? k: filename) { // use k<0 as a flag to read from filename
// ... rest of initialisation
}
also failed, because "the result of a ternary operator always has to be the same type" for compile-time reasons, as pointed out in a similar question (although they were not explained there, it seems).
Now, the inelegant solution would be to also overload the Matter constructor based on the arguments that the kap constructor should receive, but this is (1) very inelegant, especially since the Matter constructor takes many variables and performs many actions (so a lot of code would be duplicated just to vary the kap part of the constructor initialisation list), and (2) this can get out of hand if there is another class used with Matter that also has different constructors: for M classes with N c'tors, one ends up with N^ M combinations...
Would someone have a suggestion or a work-around? Thanks in advance!
If opacity has a copy constructor, you could accomplish this in the initialization list, avoiding a default constructor, but at the cost of a copy:
Matter::Matter(int i, double k, char * filename)
:kap( ( 0 < k ) ? opacity(k) : opacity( filename ) ) { ... }
You will have to live with adding a default constructor to opacity (which perhaps sets mode to 0 to indicate an invalid mode) and assign to kap in the constructor body.
Matter::Matter(int i, double k, char * filename) {
if(k > 0)
kap = opacity(k);
else
kap = opacity(filename);
}
The parameter k is a runtime value. It is not possible to make types and overloading result depend on runtime values.
To obviate copy overhead, and assuming you have a C++0x compiler, you could give opacity a move constructor and have a static function provide an instance of opacity based on your logic and initialize your kap member with the returned temporary opacity.
You'd probably want to make kappa_array some pointer like auto_ptr<double>. Though if this data is used in a tight-loop, the savings from moveability may be dubious compared to the cost of locality and dereferencing the pointer.
opacity& get_opacity(double k, char * filename) {
if(k > 0)
return opacity(k);
else
return opacity(filename);
}
Matter::Mater(int i, double k, char * filename)
: kap(get_opacity(k, filename) {
//...
}
opacity::opacity(opacity&& other)
: mode(other.mode),
kap_const(other.kap_const),
kappa_array(std::move(kappa_array)) { }
Please don't test me on this, I'm pretty new with move semantics and rvalue references myself...
You can't use a ternary operator to select function overrides because the result of the operator only has a single type. In the case where the different branches have different types, they will be coerced to the result type or there will be a compile time error. See http://en.wikipedia.org/wiki/%3F:#Result_type
It couldn't really be any other way. Types need to be known by the compiler at compile time, but the result of the operation isn't known until run time.