Friend func. and overloaded >> and <<

This is a discussion on Friend func. and overloaded >> and << within the C++ Programming forums, part of the General Programming Boards category; I checked the FAQ on this, and someone had posted this very same question before, but the solution doesn't work ...

  1. #1
    Kill Clear Channel Kheila's Avatar
    Join Date
    Oct 2005
    Location
    St. Paul, MN
    Posts
    23

    Friend func. and overloaded >> and <<

    I checked the FAQ on this, and someone had posted this very same question before, but the solution doesn't work for me. I have a class declaration (CFract) in a header file, and under the public section I have this:
    Code:
    friend istream& operator>>(istream&, CFract&);
    friend ostream& operator<<(ostream&, CFract&);
    In a source file, I have this (not within the main function, that's in a different source file):
    Code:
    ostream& operator<<(ostream& os, CFract& rF)
    {
    	if (rF.denom==1)
    		os << rF.num;
    	else
    		os << rF.num << "/" << rF.denom;
    
    	return os;
    }
    
    istream& operator>>(istream& is, CFract& rF)
    {
    	char c;
    
    	is >> rF.num >> c >> rF.denom;
    
    	return is;
    }
    Visual C++ says istream and ostream cannot access the private variables of the class CFract (num and denom). There's no reason why the istream and ostream functions shouldn't be able to access them. The solution in the FAQ I found was to put the #include<iostream> and using namespace std; statements at the top (duh), and the person says that fixed the problem...but I always had those statements, and it still doesn't work. I remembered to include the header file (yes, using quotation marks). Any ideas? I'll post the full code if necessary.
    to Absent Toast

  2. #2
    Registered User
    Join Date
    Jan 2005
    Posts
    7,317
    You may have to post the full code, or at least a small compilable version of it that still demonstrates the error.

    I seem to remember that there might be a bug in the compiler that causes it to have a problem with these kinds of friends, but I'm not sure.

  3. #3
    ^ Read Backwards^
    Join Date
    Sep 2005
    Location
    Earth
    Posts
    282
    VC++ Has problems with friend functions.
    If you are using VC++ 6.0, it was fixed in the service pack 6 release.
    http://www.microsoft.com/downloads/d...DisplayLang=en

    See if that is your problem.

  4. #4
    Kill Clear Channel Kheila's Avatar
    Join Date
    Oct 2005
    Location
    St. Paul, MN
    Posts
    23
    Haha, finally I'm right and the compiler's wrong (I hope)! Makes me feel smart I can't upgrade the software on this computer because it belongs to my school, but I'll re-compile it in Dev-C++ when I get home and see if it works. Here's the code, anyways...

    Header file:
    Code:
    /*******************
    fraction.h
    12/1/05
    by Meghan
    *******************/
    
    #include<iostream>
    using namespace std;
    
    #ifndef FRACTION_H
    #define FRACTION_H
    
    
    class CFract
    {
    public:
    	CFract();
    	CFract(int, int);
    	const CFract(CFract&);
    	~CFract(){}
    	CFract& operator=(CFract&);
    	CFract operator+(CFract&);
    	CFract operator-(CFract&);
    	CFract operator*(CFract&);
    	CFract operator/(CFract&);
    	int operator==(CFract);
    	int operator!=(CFract);
    	friend istream& operator>>(istream&, CFract&);
    	friend ostream& operator<<(ostream&, CFract&);
    
    private:
    	int num;
    	int denom;
    	void lowTerms();
    	int gcd(int larger, int smaller);
    	
    
    };
    
    
    
    
    #endif
    Relevant portion of one of the source files:
    Code:
    /*******************
    fraction.cpp
    12/1/05
    by Meghan
    *******************/
    #include<iostream>
    #include "fraction.h"
    
    using namespace std;
    
    CFract::CFract()
    {
    	num = 0;
    	denom = 0;
    }
    
    CFract::CFract(int pnum, int pdenom)
    {
    	num = pnum;
    	denom = pdenom;
    }
    
    CFract::CFract(CFract& rF)
    {
    	num = rF.num;
    	denom = rF.denom;
    }
    
    CFract& CFract::operator =(CFract& rF)
    {
    	if(&rF != this)
    	{
    		num = rF.num;
    		denom = rF.denom;
    	}
    
    	return (*this);
    }
    
    CFract CFract::operator +(CFract& rF)
    {
    	CFract temp;
    
    	temp.num = num * rF.denom + denom * rF.num;
    	temp.denom = denom * rF.denom;
    	temp.lowTerms();
    
    	return temp;
    }
    
    CFract CFract::operator -(CFract& rF)
    {
    	CFract temp;
    
    	temp.num = num * rF.denom - denom * rF.num;
    	temp.denom = denom * rF.denom;
    	temp.lowTerms();
    
    	return temp;
    }
    
    CFract CFract::operator *(CFract& rF)
    {
    	CFract temp;
    
    	temp.num = num * rF.num;
    	temp.denom = denom*rF.denom;
    	temp.lowTerms();
    
    	return temp;
    }
    
    CFract CFract::operator /(CFract& rF)
    {
    	CFract temp;
    
    	temp.num = num * rF.denom;
    	temp.denom = denom * rF.num;
    	temp.lowTerms();
    
    	return temp;
    }
    
    ostream& operator<<(ostream& os, CFract& rF)
    {
    	if (rF.denom==1)
    		os << rF.num;
    	else
    		os << rF.num << "/" << rF.denom;
    
    	return os;
    }
    
    istream& operator>>(istream& is, CFract& rF)
    {
    	char c;
    
    	is >> rF.num >> c >> rF.denom;
    
    	return is;
    }
    to Absent Toast

  5. #5
    ^ Read Backwards^
    Join Date
    Sep 2005
    Location
    Earth
    Posts
    282
    It compiled just fine for me.
    Tell your school to keep their software up-to-date.

  6. #6
    Registered User
    Join Date
    Jun 2005
    Posts
    6,259
    Having a "using namespace std;" is a header file is bad practice. Apart from the fact that the approach you're using can trip over compiler deficiencies, it can also introduce ambiguities in code which uses those header files.

    I would suggest changing your code to;
    Code:
    #ifndef FRACTION_H
    #define FRACTION_H
    
    #include<iostream>    // no point in doing this outside the include guard
    
    // no using directive
     
    class CFract
    {
    public:
            // various functions unrelated to your problem removed
    
    	friend std::istream& operator>>(std::istream&, CFract&);
    	friend std::ostream& operator<<(std::ostream&, CFract&);
    
    private:
    	int num;
    	int denom;
    	void lowTerms();
    	int gcd(int larger, int smaller);
    };
    and
    Code:
    #include "fraction.h"
    
    // no using directive here either
    
    // other functions irrelevant to the problem removed
    
    std::ostream& operator<<(std::ostream& os, CFract& rF)
    {
    	if (rF.denom==1)
    		os << rF.num;
    	else
    		os << rF.num << "/" << rF.denom;
    
    	return os;
    }
    
    std::istream& operator>>(std::istream& is, CFract& rF)
    {
    	char c;
    
    	is >> rF.num >> c >> rF.denom;
    
    	return is;
    }
    I'd also suggest a bit of usage of the const keyword (eg outputting an object to a stream is not usually an operation which changes the object) but that's another issue.

Popular pages Recent additions subscribe to a feed

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21