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);
}
Related
While i was trying to put object type to same object type of array, I am not sure how to put this.
Drink *a = new Drink("Whole Milk", 2.50, NEAT);
c.drinkArray[c.drinkCount++] = a;
Can anyone help me?
I am from java so I am so confused.....
As said try to avoid "new" in C++, I also tend to avoid 'C' style arrays (unless there is a clear benefit). 'C' style arrays don't have length checks and you can easily run into problems with writing out of bounds of the array and you will have to do some extra checking yourself.
#include <string>
#include <vector>
// not really sure what NEAT is
// but at least it can be made typesafe like this
enum class DrinkAttribute
{
UNKNWON,
NEAT,
};
struct Drink
{
std::string name = "no drink";
double price = 0.0;
DrinkAttribute attribute = DrinkAttribute::UNKNWON;
};
// put array and size information together including checks
struct Drinks
{
void add(const Drink& drink)
{
if (number_of_drinks < max_number_of_drinks)
{
drinks[number_of_drinks] = drink;
number_of_drinks++;
}
else
{
// some error handling here
}
}
Drink& get(std::size_t n)
{
if (n < number_of_drinks)
{
return drinks[n];
}
else
{
// some error handling here
// and return a drink representing no drink
// so all control paths return a value
// note I would probably just throw a std::invalid_argument exception here
// but I consider exception handling to be out of the scope of the question.
return no_drink;
}
}
static const std::size_t max_number_of_drinks = 10;
Drink drinks[max_number_of_drinks];
Drink no_drink;
std::size_t number_of_drinks = 0;
};
void ShowDrinksWithVector()
{
// to make dynamic collections of something you're bettor of using std::vector
// instead of arrays. This way you reuse tested code!
std::vector<Drink> drinks;
// at a drink to the collection of drinks
// the 3 arguments passed to emplace_back are used
// to construct an object of type Drink
drinks.emplace_back("Whole Milk", 2.50, DrinkAttribute::NEAT);
}
void ShowDrinksWithArray()
{
// this way you will have to write memory access checking code yourself
// that's why you will end up with an extra class (or you have to resort
// to using global variables)
Drinks drinks;
drinks.add(Drink{ "Whole Milk", 2.50, DrinkAttribute::NEAT });
auto drink = drinks.get(0);
}
int main()
{
ShowDrinksWithVector();
ShowDrinksWithArray();
}
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.
I have a class Itch that is a member of the class Scratch. I want to do some computations in the Scratch constructor and pass the result of these computations to instantiate the Itch object. My best guess in doing this is below, but this returns garbage:
#include <iostream>
class Itch {
public:
int N;
Itch(int n) {N = n;}
};
class Scratch {
private:
int N;
public:
Itch it;
Scratch(int n);
};
Scratch::Scratch(int n) : it(N) // here is where I want to use new data
{
// do some silly things
int temp = 5;
temp += n + 45;
N = temp - 1;
}
int main() {
int n = 1;
Scratch sc(n);
std::cout << sc.it.N << "\n";
}
Is there a standard way to do this?
The things in the initializer list happen before the things in the constructor code. Therefore, you cannot affect anything in the initializer list with the code in the constructor. You have a few options.
A reasonable approach would be to have an Itch * member rather than an Itch, and initialize it when it's ready, e.g.:
class Scratch {
...
Itch *it;
...
};
Scratch::Scratch(int n) : it(NULL)
{
// do some silly things
int temp = 5;
temp += n + 45;
N = temp - 1;
it = new Itch(N); // <- now you have enough info to instantiate an Itch
}
And you'll have to remember to clean up in the destructor unless you use an auto_ptr:
Scratch::~Scratch () {
delete it;
}
Another reasonable approach would be to pass n to the Itch constructor and have it do the calculations there instead of in Scratch, perhaps even allowing Itch to determine N, e.g.:
class Itch {
private:
int N;
public:
Itch (int n);
int getN () const { return N; }
}
Itch::Itch (int n) {
// do some silly things
int temp = 5;
temp += n + 45;
N = temp - 1;
}
Scratch::Scratch (int n) : it(n) {
// you can either remove Scratch::N altogether, or I suppose do:
N = it.getN();
// ... do whatever makes sense, try not to have redundant data.
// (also ask yourself if Scratch even *needs* to know N, or at
// least if it can just use it.getN() everywhere instead of
// keeping its own copy.)
}
Another approach, which IMO is a bit odd but it's still possible in some situations, is to have e.g. a static function (member or not) that computes N from n, which you can use in the initializer list, e.g.:
static int doSillyThings (int n) {
int temp = 5;
temp += n + 45;
return temp - 1;
}
Scratch::Scratch(int n) : N(doSillyThings(n)), it(N)
{
}
Choose whichever leads to the cleanest, most maintainable and easy-to-read code. Personally I'd prefer the first, Itch * option, since it makes logical sense and is very clear: You do the calculations necessary to initialize the Itch, then you initialize it.
You should think about your code a bit. If the Scratch's N is always equal to it.N, then do you really need both Ns?
There are other options too (including restructuring your code completely so you don't have to have an Itch member of Scratch, or so that you don't have to have it depend on extra calculations done on the Scratchs constructor parameters but that really depends on the situation), but hopefully that inspires you a little.
The reason your code returns garbage, by the way, is because N is garbage at the point you pass it to the Itch constructor. It's uninitialized until you initialize it, and at the point where it(N) is you haven't initialized N yet.
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();
}
#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.