Thread: overloading ofstream operator

  1. #1
    unleashed alphaoide's Avatar
    Join Date
    Sep 2003
    Posts
    696

    overloading ofstream operator

    Okay, I'm clueless about the error that I got for these codes.
    Here's the error:
    e:\jdocument\csci\231\no1\date.cpp(132) : error C2666: '<<' : 13 overloads have similar conversions
    and here's the codes:
    Code:
    //****************************************
    // date.h
    //******************************************
    #ifndef DATE_H
    #define DATE_H
    
    #include <fstream>
    using std::ofstream;
    using std::ifstream;
    
    class Date {
    public:
    	Date(const int = 1, const int = 1, const int = 1900);
    
    	int getMonth(void) const;
    	int getDay(void) const;
    	int getYear(void) const;
    
    	void setMonth(const int);
    	void setDay(const int);
    	void setYear(const int);
    
    	// post-increment day
    	Date& operator++(void);
    
    	// pre-increment day
    	Date operator++(int);
    
    	friend ofstream &operator<<(ofstream&, const Date&);
    	friend ifstream &operator>>(ifstream&, Date&);
    
    	bool isLeapYear(int) const;
    	bool endOfMonth(int) const;
    private:
    	int month;
    	int day;
    	int year;
    
    	void incrementDay(void);
    };
    
    #endif
    
    //***********************************
    //  date.cpp
    //**********************************
    .
    .
    .
    
    ofstream &operator<<(ofstream& stream, const Date& d){ //error 
    
    	stream << d.getMonth() << '|'
    		   << d.getDay() << '|'
    		   << d.getYear() << '|';
    
    	return stream;
    }
    .
    .
    .
    I'm not sure if codes above are sufficient to figure out what causes the error. I'll upload the whole date.cpp if necessary
    Thnx

  2. #2
    Registered User
    Join Date
    Mar 2002
    Posts
    1,595
    The purpose of declaring a function to be a friend is so it can access the private and protected data members of a class without having to use the public access methods. The syntax you are using isn't wrong, but you could make things a little more "natural" by doing this:

    stream << d.month << '|' << d.day<< '|' << d.year << '|';

    as long as you've gone to the trouble of making the operator a friend anyway.

    As to the error message, I haven't a clue. Might it be that the << operator is a already overloaded for a Date class that the compiler has already created so you're creating an ambiguous call?

  3. #3
    unleashed alphaoide's Avatar
    Join Date
    Sep 2003
    Posts
    696
    I don't overload the operator << twice (that's what I'm aware of) so, I guess I need to post the whole date.cpp. I use visual studio 6 to compile it. Thanks for any help beforehand.
    Code:
    //**********************
    // date.cpp
    //**********************
    #include "Date.h"
    
    Date::Date(const int m, const int d, const int yr) {
    	setMonth(m);
    	setDay(d);
    	setYear(yr);
    }
    
    int Date::getMonth(void) const {
    	return month;
    }
    
    int Date::getDay(void) const {
    	return day;
    }
    
    int Date::getYear(void) const {
    	return year;
    }
    
    void Date::setMonth(const int m) {
    	if ((m >= 1) && (m <= 12)) {
    		month = m;
    	}
    	else {
    		month = 1;
    	}
    }
    
    void Date::setDay(const int d) {
    	if (month == 2) { // february
    		if ((isLeapYear(year) == true)) {
    			if ((d >= 1) && (d <= 29)) {
    				day = d;
    			}
    			else { // day out of range
    				day = 1;
    			}
    		}
    		else { // not leap year
    			if (( d >= 1) && (d <= 28)) {
    				day = d; 
    			}
    			else { // day out of range
    				day = 1;
    			}
    		}
    	}
    	else { // not february
    		switch (month) {
    			case 1:
    			case 3:
    			case 5:
    			case 7:
    			case 8:
    			case 10:
    			case 12:
    				if ((d >= 1) && (d <= 31)) {
    					day = d;
    				}
    				else {
    					day = 1;
    				}
    				break;
    			case 4:
    			case 6:
    			case 9:
    			case 11: 
    				if ((d >= 1) && (d <= 30)) {
    					day = d;
    				}
    				else {
    					day = 1;
    				}
    				break;
    		}
    	}
    
    }
    
    void Date::setYear(const int yr) {
    	if ((yr >= 1900) && (yr <= 2100)) {
    		year = yr;
    	}
    	else {
    		year = 1900;
    	} 
    }
    
    bool Date::isLeapYear(int yr) const {
    	// year is leap if it is divisible by 4
    	// except if it is divisible by 100
    	// except if it is divisible by 400
    	if (
    		(yr % 400 == 0)
    		 ||
    		(yr % 100 != 0 && yr % 4 == 0)
    	   ) {
    
    		return true;
    	}
    	else {
    		return false;
    	}
    }
    
    Date& Date::operator++(void) {
    	incrementDay(); // increment object
    
    	return *this; // return for d2 = ++d1
    }
    
    Date Date::operator++(int) {
    	Date tmp = *this; // store pre-incremented value
    
    	incrementDay(); // increment object
    
    	return tmp;
    }
    
    ofstream &operator<<(ofstream& stream, const Date& d){
    	stream << d.getMonth() << '|'
    		   << d.getDay() << '|'
    		   << d.getYear() << '|';
    
    	return stream;
    }
    
    ifstream &operator>>(ifstream& stream, Date& d){
    	int tmp;
    
    	stream >> tmp;
    	d.setMonth(tmp);
    	stream.ignore();
    
    	stream >> tmp;
    	d.setDay(tmp);
    	stream.ignore();
    
    	stream >> tmp;
    	d.setYear(tmp);
    	stream.ignore();
    
    	return stream;
    }
    
    void Date::incrementDay(void) {
    	if (!endOfMonth(day)) {
    		day = day + 1;
    	}
    	else { // end of month
    		if (month < 12) {
    			month = month + 1;
    			day = 1;
    		}
    		else { // December end of month
    			year = year + 1;
    			month = 1;
    			day = 1;
    		}
    	}
    }
    
    bool Date::endOfMonth(int d) const {
    	if (month == 2) { // February
    		if ((isLeapYear(year) == true) && (d == 29)) {
    			return true;
    		}
    		else if ((isLeapYear(year) == false) && (d == 28)) {
    			return true;
    		}
    		else {
    			return false;
    		}
    	}
    	else { // not February
    		switch (month) {
    			case 1:
    			case 3:
    			case 5:
    			case 7:
    			case 8:
    			case 10:
    			case 12:
    				if (d == 31) {
    					return true;
    				}
    				else {
    					return false;
    				}
    				break;
    			case 4:
    			case 6:
    			case 9:
    			case 11:
    				if (d == 30) {
    					return true;
    				}
    				else {
    					return false;
    				}
    				break;
    		}
    	}
    }

  4. #4
    Amateur
    Join Date
    Sep 2003
    Posts
    228
    After trying your code, I figured out what was not going fine.
    It is not that an overloaded operator for a Date class already exists.
    And, actually, the error isn't where you think it is.
    Look at this small part of code:
    Code:
    stream << d.getMonth()
    Here lies the error, you're trying to use the << operator on a stream and an int. But this operation is ambigous! Because there are two operators defined.

    Well, "How could it be, it is the STL!", could you say.
    But it is not that, it's *you* who created the error. Because you defined a compatible operator for this case. Yes, you only defined one operator:
    Code:
    friend ofstream &operator<<(ofstream&, const Date&);
    Here, you define a const object reference parameter.
    Code:
    Date(const int = 1, const int = 1, const int = 1900);
    And here, a constructor that has its second and third parameter set to a default value; the constructor can take one int as entry then.

    From that, you can say that the second overloaded operator is your own!
    Last edited by lyx; 09-29-2003 at 12:48 PM.

  5. #5
    unleashed alphaoide's Avatar
    Join Date
    Sep 2003
    Posts
    696
    Wow, awesome info
    I still need to grasp it, though. But don't worry I will. I guess I have to rewrite my constructor, you'd say?
    Thanks a bunch, I learned a lot today!

  6. #6
    Amateur
    Join Date
    Sep 2003
    Posts
    228
    What is to grasp anyway? ^^ I think it would be something like having a hold on smth, but I'm not sure.
    Don't worry if you didn't know that, C++ is much trickier than most languages I think.
    By the way, no, you don't have to rewrite your constructor. I'll give you two simple solutions:
    - Change the prototype so it does not accept one int entry anymore by removing the default parameters for at least the first and the second arguments.
    - Make your constructor explicit. This is the best solution. I suppose you don't know what I'm talking about, so here's some code:
    Code:
    explicit Date(const int = 1, const int = 1, const int = 1900);
    That way, the compiler won't try to do the conversion by himself.

    Hope it will help, but I couldn't help more this evening, I don't think I'm going to be on the board as I have to do my homeworks. Really anoying things that are; besides it is neither Maths nor English. (the two subjects I'm the best at ^^) Got to work on my geography test for tomorow.

  7. #7
    Registered User
    Join Date
    Jul 2003
    Posts
    450
    I don't think I grasped the reply either but thanks elad about the accessor methods in the friends overloaded function! I was wondering the same thing in another post. May have to edit some of my code.

  8. #8
    Amateur
    Join Date
    Sep 2003
    Posts
    228
    Do I really explain that bad? -_-
    Sorry, mother is shouting at me so better hurry doing my homeworks, don't have the time to explain more clearly.

  9. #9
    Registered User
    Join Date
    Mar 2002
    Posts
    1,595
    Code:
    lyx certainly seems to know his/her stuff.  As an alternative, instead of trying to do everything in a single constructor like this:
    
    Date(const int = 1, const int = 1, const int = 1900);
    
    and getting tripped up as lyx described you could try this combination as an alternative to the solutions lyx described:
    
    //default constructor to initialize data members with default values
    Date() : month(1), day(1), year(1900)
    {}
    
    //in combination with a three int constructor to allow user input
    Date(int m, int d, int y) : month(m), day(d), year(y)
    {}
    
     //and then the routine syntax for the << operator, inlined here
    //for simplicity sake
     friend ofstream &operator<<(ofstream& stream, const Date& d)
    { 
      stream << d.month << '|' << d.day << '|' << d.year << '|';
      return stream;
    }

  10. #10
    unleashed alphaoide's Avatar
    Join Date
    Sep 2003
    Posts
    696
    Thanks, elad for the alternative. I thought that was the only solution possible also, but I added "explicit" to the the prototype like lyx says, and it works flawlessly. I got fewer lines of codes also writing just one constructor.

  11. #11
    Registered User
    Join Date
    Mar 2002
    Posts
    1,595
    And that's great as long as you know what you are doing and you can comment the code so the people trying to maintain your code down the road know what you are trying to do.

  12. #12
    Amateur
    Join Date
    Sep 2003
    Posts
    228
    Actually, I was just saying that C++ standard says that your constructors are all implicit by default, that means that for a constructor that takes only one argument, you can write
    Code:
    class object = type;
    Instead of
    Code:
    class object = class(type);
    But it implies that, if you pass an object to a function, the parameter is automatically built into the object.
    Then when an argument to a function is a constant reference to an object - const class& - the compiler automatically tries to build the object by himself with the parameter passed like if it were an object.
    The explicit keyword forces you compiler to ignore the implicit syntax.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. unary operator overloading and classes
    By coletek in forum C++ Programming
    Replies: 9
    Last Post: 01-10-2009, 02:14 AM
  2. Smart pointer class
    By Elysia in forum C++ Programming
    Replies: 63
    Last Post: 11-03-2007, 07:05 AM
  3. Operator Overloading (Bug, or error in code?)
    By QuietWhistler in forum C++ Programming
    Replies: 2
    Last Post: 01-25-2006, 08:38 AM
  4. C++ Operator Overloading help
    By Bartosz in forum C++ Programming
    Replies: 2
    Last Post: 08-17-2005, 12:55 PM
  5. operator overloading and dynamic memory program
    By jlmac2001 in forum C++ Programming
    Replies: 3
    Last Post: 04-06-2003, 11:51 PM