#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.
Related
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.
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 am just starting out with C++. I have a class ourVector and within that class I have a constructor that is named ourVector() as well and it includes the initializations of variables. I need these variables to reset with every loop in main, but I can't figure out how to call the constructor in main.
class ourVector
ourVector()
{
vectorCap = 20;
vectorSize = 0;
}
In main my class object is called ourVector vectorTest;
I just would like to figure out how to call ourVector() without getting an error so I can place it at the end of my loop in main to clear and re-initialize the variables.
Any help would be greatly appreciated.
Thank you!
Usually when you find yourself doing things like this it's a sign that maybe there's a more semantically appropriate way to structure your code (i.e. make the code structure more closely represent your intent).
In your case, ask yourself why you need to reset the value every time through the loop. It seems like you are just using your object to hold some intermediate data on each iteration through the loop, and you aren't concerned about the values outside of the loop (but if you are, you want something like riderBill's answer). So really, your ourVector instance is only useful within the scope of that loop.
So make your code structure reflect that:
int main () {
...
while (...) { // <- this represents your loop
ourVector v; // <- each time through, 'v' is constructed
... // <- do whatever with 'v' here
} // <- that 'v' goes away when it goes out of scope
...
}
In other words, just declare it in the loop, where it belongs. Semantically this makes sense (it represents how and where you're actually using the object), and it does what you want without modification to your ourVector.
In general, as a beginner's rule of thumb, try to declare variables in the tightest scope possible that still works for your code.
The constructor is only called when instantiating an object; you cannot explicitly call it to reinitialize your variables. But you can call public member setter function(s) from the constructor. Then you can call the setter function(s) again from within your loop.
class ourVector
{ int vectorCap ;
int const defaultVectorCap = 20; // No magic numbers!
int vectorSize ;
int const defaultVectorSize = 0;
int roomToGrow ; // To illustrate a point about setters.
public:
// Constructors
ourVector() // Use this constructor if you don't know the proper initial values
// (you probably always do or never do).
{ setVectorCap (defaultVectorCap );
setVectorSize(defaultVectorSize);
} // End of default constructor
ourVector( int vecCap, int vecSize) // Lining stuff up improves readability
{ setVectorCap (vecCap ); // (e.g. understanding the code and
setVectorSize( vecSize ); // spotting errors easily).
// It has helped me spot and avoid
// bugs and saved me many many hours.
// Horizontal white space is cheap!
// --Not so forvertical white space IMHO.
// Setters
void setVectorCap(int vecCap)
{ vectorCap = vecCap;
// I might need this internally in the class.
// Setters can do more than just set a single value.
roomToGrow = vectorCap - vectorSize;
} // End of setVector w/ parameter
void setVectorSize(int vecSize)
{ vectorSize = vecSize;
roomToGrow = vectorCap - vectorSize; // Ok, redundant code. But I did say
// "As much as practical...."
} // End of setVectorCap w/ parameter
void setVectorSize() // Set to default
{ // Don't just set it here--leads to poor maintainability, i.e. future bugs.
// As much as practical, redundant code should be avoided.
// Call the setter that takes the parameter instead.
setVectorSize(defaultVectorSize);
} // End of setVectorSize for default size
void setVectorCap() // Set to default
{ setVectorCap (defaultVectorCap );
} // End of setVectorCap for default size
}; // End of class ourVector
#include <cstdio>
#include <cstdlib>
#include "ourVector.hpp"
int main(int argc, char *argv[]);
void doSomething(ourVector oV );
int main(int argc, char *argv[])
{ ourVector oV;
// Or, if you want non-default values,
//int mySize = 2;
//int myCap = 30;
//ourVector(mySize, myCap);
for (int i = 0; i<10; i++)
{ // Set fields to original size.
oV.setVectorSize();
oV.setVectorCap ();
// Or
//oV.setVectorSize(mySize);
//oV.setVectorCap (myCap );
// Whatever it is your are doing
// ...
}
// Do whatever with your vector. If you don't need it anymore, you probably should
// have instantiated it inside the for() block (unless the constructor is
// computationally expensive).
doSomething(oV);
return 0;
} // End of main()
void doSomething(ourVector oV) {}
This code works:
class ourVector
{
public:
ourVector() : vectorCap(20), vectorSize(0) { };
ourVector(int c, int s) : vectorCap(c), vectorSize(s) { };
void setVCap(int v)
{
vectorCap = v;
}
void setVSize(int v)
{
vectorSize = v;
}
int getVCap()
{
return vectorCap;
}
int getVSize()
{
return vectorSize;
}
void print()
{
std::cout << vectorCap << ' ' << vectorSize << '\n';
}
private:
int vectorCap;
int vectorSize;
};
int main()
{
ourVector vectorTest(5,5);
vectorTest.print();
vectorTest.setVCap(6);
vectorTest.setVSize(6);
vectorTest.print();
std::cout << vectorTest.getVCap() << ' ' << vectorTest.getVSize() << '\n';
vectorTest = ourVector();
vectorTest.print();
}
The ourVector() : vectorCap(value), vectorSize(value) { }; parts are the initializers. The vectorCap(value) part sets vectorCap to value; the { } section is an empty method, use this to do any calculations and verifications you need. The SetVCap(int) and SetVSize(int) methods can be called to change the values of vectorCap and vectorSize, respectively. getVCap() and getVSize() return the values of vectorCap and vectorSize respectively.
In my example, you do not need to validate the code, so the initializers ourVector() : vectorCap(value), vectorSize(value) { }; work perfectly fine. If you need to validate the input, you may wish to call the assignment functions from the initializer so you only need to implement the validation once, which makes debugging easier. To do this, just replace the constructors with these constructors. Now you need only validate the input in one place:
ourVector()
{
setVCap(20);
setVSize(0);
}
ourVector(int c, int s)
{
setVCap(c);
setVSize(s);
}
This question already has answers here:
Constructor to specify zero-initialization of all builtin members?
(3 answers)
Closed 8 years ago.
What is the best way to make sure the following large struct always has its integers initialized to 0?
struct Statistics {
int num_queries;
int num_respones;
// ... 97 more counters here
int num_queries_filtered;
}
I would like to avoid having to check each place this struct is initialized to make sure it is value initialized with Statistics s(); rather than default initialized with Statistics s;.
Statistics s; // Default initialized by accident here
s.num_queries++; // Oh no, this is a bug because it wasn't initialized to zero
Statistics s2{}; // Correctly value initialized
s2.num_queries++; // Successful
Proposal 1 - Use memset, but this feels like a hack where we take advantage of the value initialization happening to be equivalent to 0 filling the data structure:
struct Statistics {
Statistics() { memset(this, 0, sizeof(*this)); }
// ... counters here
}
Proposal 2 - Use constructor initialization lists, but this is cumbersome and when people add new counters in the future they may forget to zero-initialize them in the constructor:
struct Statistics {
Statistics() : num_queries(0), num_respones(0), /* ... */, num_queries_filtered(0) {}
// ... counters here
}
Proposal 3 - Force the value initialization to take place as follows:
struct StatisticsUnsafe {
// ... counters here
}
struct Statistics : public StatisticsUnsafe {
Statistics() : StatisticsUnsafe() {}
}
What do you feel is the best approach? Do you have other alternatives?
EDIT I want to clarify that in my actual code, each of the counters has a meaningful name, such as "num_queries_received", "num_responses", etc. Which is why I do not opt to use a vector or array of the form "counters[100]"
EDIT2 Changed the example from Statistics s2(); to Statistics s2{};
From C++11, you may also do:
struct Statistics {
int counter1 = 0;
int counter2 = 0;
// ... more counters here
int counter100 = 0;
};
Unless you have a fairly specific reason to do otherwise, your first choice should probably be a std::vector, such as:
std::vector<int> Statistics(100);
This will zero all the contents automatically. You can address an individual counter in the array as something like:
++Statistics[40];
...which will increment the 41st item (the first is Statistics[0]).
If the size if really fixed at 100 (or some other number you know at compile time) you might prefer to use std::array instead:
std::array<int, 100> Statistics;
This is potentially a little faster and usually uses a (little) less memory, but fixes the size (whereas with an std::vector you can use push_back, erase, etc., to add and remove items).
Given the edited question (the objects really aren't array-like) I'd probably consider something a little different, probably something like this:
template <class T>
class inited {
T val;
public:
inited(T val=T()) : val(val) {}
operator T() const { return val; }
operator=(T const &newval) { val = new_val; }
};
struct Statistics {
inited<int> sum;
inited<int> count;
inited<double> mean;
};
Then an inited<T> is always initialized to some value--you can specify a value if you wish, and if you don't specify any, it uses value initialization (which will give zero for arithmetic types, a null pointer for a pointer type, or use the default constructor for types that define one).
Since it defines an operator T and an operator=, you can still assign to/from elements, just about like usual:
Statistics.sum = 100;
Statistics.count = 2;
Statistics.mean = static_cast<double>(Statistics.sum) / Statistics.count;
You might prefer to use a single:
operator T&() { return val; }
Instead though. This supports both reading and writing (as above) but also compound assignment operators (e.g., += and -=).
Have you considered writing an initializer for each data member?
struct Statistics {
typedef int counter_t;
counter_t counter1 = 0;
counter_t counter2 = 0;
// ... more counters here
counter_t counter100 = 0;
};
Note that if you include such initializers, though, the struct is no longer an aggregate, and hence can't be initialized using aggregate initialization via a braced list. Whether that matters or not for this type is hard to say.
Well you certainly can do something like:
struct Statistics {
int counter1 = 0;
int counter2 = 0;
// ... more counters here
int counter100 = 0;
};
This is perfectly valid in c++11. But the question is, do you really need this? Wouldn't it be more convenient to use a vector?
struct Statistics {
std::vector<int> counters = std::vector<int>(100, 0);
};
And if vector is not an option, you can do some magic in constructor:
struct Statistics {
int counter1;
int counter2;
// ... more counters here
int counter100;
Statistics() {
for (int * i : {&counter1, &counter2, ..., &counter100 }) {
*i = 0;
}
}
};
Statistics s;
s.counter2; // now stores 0 or anything you like.
Here is a C-like way:
#include <assert.h>
#include <cstring>
#include <type_traits>
struct Statistics {
int counter1;
int counter2;
int counter3;
int counter4;
// maybe more //
Statistics() {
// checks whether Statistics is standard-layout
// to be sure that memset won't break it
static_assert(
std::is_standard_layout<Statistics>(),
"Someone broke Statistics, can't use memset to zero it.");
// initializes hole Statistics's memory by zeros
memset(this, 0, sizeof(Statistics));
}
};
// Here is a way how to check Statistics
void assert_Statistics() {
Statistics s;
int* ptr = reinterpret_cast<int*>(&s);
int count = sizeof(Statistics) / sizeof(int);
for (int i = 0; i < count; ++i) {
assert(*(ptr++) == 0);
}
}
int main()
{
Statistics s;
assert_Statistics();
}
I have following code:
#include <iostream>
using namespace std;
class Base
{
private:
int i;
char ch;
public:
void showdata()
{
cout<<"Int:"<<i<<endl;
cout<<"Char:"<<ch<<endl;
}
//int pub_data ;
} ;
int main()
{
Base ob;
ob.showdata() ;
//cout<<"Public Data:"<<ob.pub_data<<endl;
return 0;
}
This program compiles and runs fine. The output shows that i is initialized with 0 and ch is initialized with '\0'.
If you notice i have commented out 2 statements in this program. First the declaration of public data pub_data and second the line inside main printing this public data.
Now here the problem is, if i uncomment these two lines, the data members of class i.e. i, ch, pub_data do not seem to be initialized and when printed, they display junk values.
So my question is what difference public data makes here?
I'm using g++ 3.4.6
Neither int's nor char's are automatically initialized to 0. The fact that it happened is just luck.
You need to add a constructor that does the initialization:
Base() : i(0), ch(0) {}
None. You're just getting "lucky". Fundamental types remain uninitialized, so your i and ch, as the program stands, could very well not always be 0.
It just so happens adding that public member "messes it up". To correct your class, initialize the members in the initialization list of the constructor:
class Base
{
private:
int i;
char ch;
public:
Base(void) :
i(0), ch(0) //, pub_data(0)
{}
void showdata()
{
cout<<"Int:"<<i<<endl;
cout<<"Char:"<<ch<<endl;
}
//int pub_data ;
} ;
Now when a Base gets constructed i, ch, and (when uncommented) pub_data will be properly initialized to meaningful values.
As opposed to Java or C#, where memory allocated for a newly created objects ALWAYS set to zero, this NOT happends in C++. There are several rules that describe when object initialization is guaranteed to take place and when it isn't.
Consider folowing example:
class Base
{
private:
int i;
char ch;
std::string str;
public:
Base()
: i(0) //built-in fields remains unitialized. We should initialize it manually
, ch('\0') //another built-in field
//, str() //this call is redundant due automatic default constructors calls for all user-defined types
{}
void showdata()
{
cout<<"Int:"<<i<<endl; //valid only after manual initialization
cout<<"Char:"<<ch<<endl; //valid only after manual initialization
cout<<"String:"<<str<<endl; //always valid
}
//int pub_data ;
} ;
You should remember, that ALL buit-in fields you should initialized manually in class constructor.
P.S. The fact, that in the first case your code works - is pure accident.
What has been answered already is correct, but to make sure your values are zero-initialized you can also simply declare your object as
Base ob(); // notice the parentheses here
or
Base ob{}; // this compiles only on c++11
For more details, check out this insightful answer:
https://stackoverflow.com/a/620402/3073460