1

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!

calrol2009
  • 17
  • 4
  • In the first place, why don't you create private and public variables/methods to change these values? In the second place, you should just call something like `vectorTest = new ourVector();` if you want to reset it. –  Oct 26 '14 at 03:37
  • @hosch250: Except without the `new`. – Ben Voigt Oct 26 '14 at 03:50
  • Calrol, if your variable is declared inside the loop, the constructor will be rerun *automatically* on every iteration. You don't call the constructor by hand. – Ben Voigt Oct 26 '14 at 03:50
  • @BenVoigt Yes, I am too used to C# now. See my working answer below. Too late to edit my comment now. –  Oct 26 '14 at 03:55

3 Answers3

4

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.

Community
  • 1
  • 1
Jason C
  • 38,729
  • 14
  • 126
  • 182
  • 2
    It is not just a beginner's rule of thumb to keep your variables in the tightest scope possible - it is the only sensible thing to do, and professionals follow this rule too. –  Oct 26 '14 at 05:08
  • As a general rule, declaring and instantiating inside a loop is a good option because it keeps the object close to the logic using it, which makes coding easier. Also, the object is destroyed upon exiting the loop, freeing memory and other resources (assuming, of course, a properly written destructor). However, if substantial overhead or undesired side-effects are associated with the constructor, constructing inside a loop *may not* be the best approach. – riderBill Feb 16 '16 at 01:27
  • @Jason C. Your syntax is correct; 'ourVector v'` (without parentheses) does indeed instantiate v. My mistake. In fact, the statement `ourVector v();` is a declaration of a function, v, taking no arguments, and returning an ourVector object. See [Most vexing parse](http://stackoverflow.com/questions/1424510/most-vexing-parse-why-doesnt-a-a-work). So I'm *doubly* mistaken. Bad day for me, but thanks for the head-slap all the same. I'm falling on my sword here, but I'll delete my earlier comment; it just confuses the issue. – riderBill Feb 21 '16 at 10:19
3

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) {}
riderBill
  • 818
  • 9
  • 16
  • 5
    If he wants the object reconstructed on each iteration of the loop, put it inside the loop. No need for a special member function to redo what should be done by the constructor. – Ben Voigt Oct 26 '14 at 03:57
  • Right. If the object is only used inside the loop then he should declare it inside the loop unless the constructor is computationally expensive. I was trying to illustrate the use of public class members for setting (possibly private) class member files. In hindsight maybe my example should have two setter functions, one for each fields. I'll change the example shortly (after testing it, of course). – riderBill Oct 26 '14 at 18:23
  • I meant to say "...(possibly private) class member *fields*. – riderBill Oct 30 '14 at 04:36
  • 1
    Yeah that was already clear. Doesn't change the fact that your constructor is *doing it wrong*. You're failing to initialize your trivial data members at all, which means that the destructor can encounter garbage. Plus it requires all members to be default constructible. – Ben Voigt Oct 30 '14 at 14:29
  • @BenVoigt Several questions: Doing it wrong? Do you mean by not having an initializer list for the trivials? Please explain about the destructor encountering garbage--it shouldn't care about the *values* of the non-pointer fields (right?). I wanted to illustrate the point that the same public members used to set initial values can be called *externally*, which is (sometimes) a good idea since it improves maintainability in the case that later I decide add to the setters, i.e. to calculate *other* field values when the target field is set. – riderBill Oct 31 '14 at 15:10
  • @BenVoigt: You are correct that the setters should have parameters. I'll change that. In that case the constructor should also take arguments. It might be better to override the constructor to provide the option for default or user supplied values--I will do that also. I was trying to keep the focus narrow, but you are right that I should provide better example code. – riderBill Oct 31 '14 at 15:11
  • Why wouldn't it care about the values of the non-pointer fields? Usually, a container's internal size field controls how many element destructors will be called by the container destructor. If that size is garbage... Some cases exist where you don't have to care, like if the elements are primitives and you aren't calling any destructors, but that leaves you the choice of proving and documenting that garbage isn't a problem, or just habitually preventing garbage from being seen in the first place. Using the initializer list as designed is just a better habit. – Ben Voigt Oct 31 '14 at 15:50
  • @BenVoigt: So would it be better to call the setters in the initialization list? I suppose I could do that--never have. Thanks for the advice. No time to change it now. I still don't see why the internal size field would be an issue. The class knows about its size, including all fields, right? Of course if memory was allocated, that will have to be dealt with in the destructor. Destructors for internal classes will be called when the object is destroyed. Same with parent objects. Got to go. I'll think about this later. – riderBill Oct 31 '14 at 16:43
0

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);
}
  • Many cans of worms opened here. While it's useful that you explained *what* your code does, it's already fairly apparent by looking at it. It would be more helpful if you explained *why* you chose to do something like this. You also have introduced a lot of new syntax that the OP is likely unfamiliar with, and you may wish to explain this as well. You may also want to consider [using the setters from the constructor](http://stackoverflow.com/questions/18034360/java-setting-private-fields-inside-constructors/18034480#18034480), or at least mentioning when it's beneficial and when it isn't. – Jason C Oct 26 '14 at 04:31
  • @JasonC If he doesn't know this syntax, it is probably time he learns it, correct? I learned this syntax as I was learning about classes. It is a lot to learn, but that is how learning new things is. Why did I choose to do something like this? Mainly because this is what I was taught is correct. You are correct that he should probably call the setters from the constructor for reusability and changeability. Will change this. –  Oct 26 '14 at 04:54
  • Sure, but you were *taught* it. Similarly, you'd need to *teach* it, not just surprise present multiple things at once with no explanation. :) – Jason C Oct 26 '14 at 05:01
  • 1
    @JasonC OK, I agree. Actually, I taught myself it by reading Bjarne Stroustrup's book for learning C++. I will work on an update later, I have to leave soon. The best method for learning programming is reading correct code, or so I have read. –  Oct 26 '14 at 05:03
  • @hosch250 I considered using the initializer list in my example, but decided to call the setters because it better illustrated the point. I think the initializer method is preferred for *field members* (except wrt maintainability), because it is more efficient. Use of initializers for base classes is more important because it is the only way to call specific base class constructors. But that is getting too far afield from the question. – riderBill Oct 30 '14 at 04:49
  • @hosch250 BTW, IMHO the best way to learn to program is to write programs that force you to learn. Reading books on programming is also a great idea, as is looking at other programmers' codes. – riderBill Oct 30 '14 at 04:57
  • @riderBill Exactly. I think reading books is a good way to learn good techniques and habits, but reading and writing programs helps you learn these techniques and habits. –  Oct 30 '14 at 14:54