ok so I'm very new at classes and don't quite understand them much so this may seem simple.

What I have to do basically is write a program that takes in an angle (for example 149degree symbol34.8' W) and then prints it out on to the screen. I have to write a main() function that displays an angle initialized with the three argument constructor and an uninitialized angle that uses the default constructor.

Here's what I have so far:

#include <iostream>
 
using namespace std;
 
void greeting();
//Diplays the greeting.
 
class Angle
{
   public:
      Angle()
      {
          degrees = 0;
          mins = 0;
          direction = 0;
      }
      Angle(int d, double m, char di)
      {
            d = degrees;
            m = mins;
            di = direction;
      }
      ~Angle(){}
      void getAngle();
      void displayAngle();
   private:
      int degrees;
      double mins;
      char direction;
};
 
int main()
{
   char runagain;
   Angle x;
 
   greeting();
 
   do
   {
      x.getAngle();
      x.displayAngle();
 
 
      cout << endl << endl << "Do you wish to run again? y/n ";
      cin >> runagain;
      runagain = tolower (runagain);
      cout << endl;
   }
   while(runagain !='n');
 
   system("pause");
   return 0;
}
 
void greeting()
{
   cout << "This program will print out angles that the user enters.\n";
}
 
void Angle::getAngle()
{
   cout << "Please enter the number of degrees, minutes, and the direction: ";
   cin >> degrees >> mins >> direction;
}
 
void Angle::displayAngle()
{
   cout << "Angle is: " << degrees << (char)248 << mins << "'" << direction << endl;
}

I can't seem to be able to enter something that doesn't have three arguments and have it print out the default. Please help?

In that case, instead of accepting the input from user in the form of integers, accept the input in the form of string. Parse to string and find out whether the user has entered one, two, three values.

Extract the values from the string using a string stream. If he has entered less than three values, print out the default, if not, then print out the values as entered by the user.

To facilitate this, give default values out to the constructor as 0.0 so that if any one parameter is not supplied, the default value will be bound to the instance members.

Angle(int i = 0, double d = 0.0, char c = 0)
{
   inclination = i;
   degree = d;
   choice = c;
}

Also better seperate the class declaration from the definition in real scenarios.

Another possibility is to accept input using 3 separate cout+cin, which might be easier for you. Although for sake of learning string parsing basics you should try what AD suggested..
One comment on AD's code:
Default values, usually, should be invalid values e.g.
Angle(int d = 361, double m = 61, char di = 'X')

> you should try what AD suggested..
AD?

> Default values, usually, should be invalid values
Give a real life example with reasons why this should be the case. Default values actually contain _default_ values which the class instance is supposed to have. The way you put in, leaving off values would become meaningless since they would contain invalid values, not something the programmer intended.

> you should try what AD suggested..
AD?

Sorry, confused with Ancient Dragon as she mentioned.. :)

>
> Default values, usually, should be invalid values
Give a real life example with reasons why this should be the case. Default values actually contain _default_ values which the class instance is supposed to have. The way you put in, leaving off values would become meaningless since they would contain invalid values, not something the programmer intended.

Take the class in this thread itself for example, if you have 2 objects of this class one created with appropriate arguments and one not initialized correctly (used default values by mistake), then there is simply no way (programatically) one can find out which object is a "mistake" as both have valid state.
Also I said "usually", this is because there would be specific scenarios when the functionality supported by your class requires a valid default value e.g. ifstream c'tor.

AFAIK, the use of default values is for the flexible creation of objects, not identifying which objects have been created by _mistake_. And BTW, how would you justify that an object is created 'unintentionally', after all, its in the hands of the developer to dictate when an object should be created.

> Also I said "usually", this is because there would be specific
> scenarios when the functionality supported by your class requires
> a valid default value
I would rather not call it usually, but more like 'sometimes' in 'specific' cases'. :)

> e.g. ifstream c'tor.
Example with justifications please ;-)

>> AFAIK, the use of default values is for the flexible creation of objects, not identifying which objects have been created by _mistake_. And BTW, how would you justify that an object is created 'unintentionally', after all, its in the hands of the developer to dictate when an object should be created.

Def vals are not meant only for flexible "creation".
Actually I didn't mean "mistaken creation" at all. :). What I meant by "and one not initialized correctly (used default values by mistake)" is that object creation was intentional but later the programmer forgot to call getangle() on this obj, and thus it was left with default values. Now if the default values are valid values, there is no way to programmtically identify this mistake.
Instead if default values would;ve been invalid ones when this object is used error would be caught by the program itself.

> e.g. ifstream c'tor.
>> Example with justifications please ;-)
That is what this is. But I'll explain to make it more clear.. :)

//Here are the signatures
basic_ifstream(const char *s, ios_base::openmode mode = ios_base::in, long protection = 0666)
Angle(int i = 0, double d = 0.0, char c = 0)

The basic difference between values taken by argument of ifstream::ifstream() namely ios_base::openmode mode and Angle::Angle() namely double d is that
1. ios_base::openmode mode argument CAN NOT BE invalid.
2. the default value ios_base::in is actually correct for most users of ifstream.
Compare Angle's double d with this,
1. double d can have an invalid value.
2. There is no default value that can be correct for most users, infact any default value would actually be wrong for most users.

So on Angle you use invalid default values and in ifstream you give correct default values.

> there is no way to programmtically identify this mistake.
You mean something like:

int result;
for(int i = 1; i <= 10; ++i)
    result += i;

You normally don't make up for bad programming practices by changing the way things originally work. (at least in all real life scenarios).

OK, lets assume that you _somehow_ manage to check invalidity of those three fields, what would you do when stuck with a class with around 10-20 fields? There are better ways of solving the same problem / programming blunders like keeping a dirty flag which will give an indication whether the instance has been touched by other mutators before being used by accessors.

Also, it doesn't make sense to create a point object which takes no values. Point p; //doesn't make sense You would rather normally create a variable with the information available with you or delay the variable creation rather than creating them beforehand.

Remember, variables ideally should only be created just prior to their first use (esp objects).

>> there is no way to programmtically identify this mistake.
What I mean is that the code that is going to use these obj with invalid value won't be able to identify. E.g. if you have a GUI based program which draws diagrams that contain points, the code that draws the diagram would draw Point (or Angle) obj with invalid values without errors. And even if you add some/any code to this part there is no way you can identify...

>> You normally don't make up for bad programming practices by changing the way things originally work. (at least in all real life scenarios).
That's exactly what you would do if you're designing a library ! Design your interface in such a way that it helps avoid avoidable programming errors. :)

>> OK, lets assume that you _somehow_ manage to check invalidity of those three fields, what would you do when stuck with a class with around 10-20 fields?
>> There are better ways of solving the same problem / programming blunders like keeping a dirty flag which will give an indication whether the instance has been touched by other mutators before being used by accessors.
Now we're discussing this specific case, which originally was an example. :).
Ok, if we talk case by case,
1. in case when you have 10-20 fields you won't have a c'tor that takes them all as arguments (if you do you can have a review comment from me to remove it :). )
2. unfortunately the examples picked up stored the passed arguments in member variables, but default values are also used in functions where args are just used inside the function. Here you'll be looking at the validity of arguments and not the object.


>> Also, it doesn't make sense to create a point object which takes no values. Point p; //doesn't make sense >> You would rather normally create a variable with the information available with you or delay the variable creation rather than creating them beforehand.
>> Remember, variables ideally should only be created just prior to their first use (esp objects).
Agreed with the last stmt.
Creating an obj with no values was a "mistake" which can happen at anywhere in the code and by anyone. Negative scenario.
Also for a +ve scenario, I would expect, a class like Point (or Angle) wouldn't be instantiated only once, and if you have many objects you would prefer to allocate memory before hand (and say use placement new instead of normal new). This will be the case when it'll make sense to create a point object which takes no values (as u donno the values).
Then again this is "case-by-case" thing and doesn't apply when we talk of normal function arguments (point #2 above).

Bah, we are getting nowhere with all this. :) But yes, there are many ways of looking at the same thing, and digging in specifics doesn't help the cause of 'what is the real advantage of having default values for constructor parameters'. But nice discussion it was.

This article has been dead for over six months. Start a new discussion instead.