Hi,
Recently (today) got an assignment to take a particular code that we've done previously, and split it into 3 files: 2 .cpp files and a header file. Now, i believe i've done it correctly, but the only thing that's throwing up errors is the use of friend for overloading the << operator.

Here's how it was used in the previous example (class name is "complex"):

...//other class stuff
friend ostream & operator<<(ostream &os, const complex &z);
}; //end of class

ostream & operator<<(ostream &os, const complex &z)
{
	//..stuff...
}

and I've split the class declaration and function definitions across the header file and one of the .cpp files respectively, such that the header file contains this:

#ifndef COMPLEX_H
#define COMPLEX_H

using namespace std;

namespace ns1 
{
	const double pi = 3.141592;
	
	class complex
	{
		
		
	private:
		
		double re;
		double im;
		
	public:
		
		complex(){re=0; im=0;}
		complex(double real, double imag){re=real;im=imag;}
		~complex(){;}
		double getreal() const;
		double getimag() const;
		double getmod();
		double getmod2() const;
		complex getconj() const;

		complex operator+ (const complex &z) const;
		
		friend ostream & operator<<(ostream &os, const complex &z);
	};
}

#endif

and the .cpp file contains this:

#include<iostream>
#include<cstdlib>
#include<cmath>
#include "head.h"

using namespace std;
using namespace ns1;

double complex::getreal() const {return re;}
double complex::getimag() const {return im;}
double complex::getmod() {return sqrt(re*re + im*im);}
double complex::getmod2() const {return (re*re+ im*im);}
complex complex::getconj() const {complex temp(re,im*-1);return temp;}

complex complex::operator+ (const complex &z) const {complex temp(re+z.getreal(),im+z.getimag());return temp;}

ostream & operator<<(ostream &os, const complex &z)
{
	if(z.im==0)	{os<< z.re; return os;}
	else{
		if(z.im>0)	{os<< z.re << "+"<< z.im << "i"; return os;}
		else		{os<< z.re << z.im << "i"; return os;}
		}
}

Yet I'm getting the errors that would indicate because the data it's trying to access is private (i.e. z.re) it cannot use it, so it's not getting friended at all.

Could anyone let me know if this looks alright, and what could be going wrong (oh and I've tried moving the friend declaration outside of public and private to no avail.)

btw I'm using Xcode 3.2.1 if that's of any relevance

Thanks!

Dani AI

Generated

has the right fix: your friend declaration created an operator<< that belongs to namespace ns1, but you defined a different overload at global scope. The global function has no friendship, so it cannot access z.re/z.im. In C++, a friend function first declared inside a class becomes a member of the class’s enclosing namespace and is only found by ADL unless you also provide a matching namespace-scope declaration. That is why placing the definition inside namespace ns1 { ... } (or qualifying it as ns1::operator<<) resolves the access error. See the friend and ADL rules for the details. cppreference: friend declaration, cppreference: argument-dependent lookup (ADL).

A minimal pattern you can keep around (note the namespace and no using namespace std; in the header):

// complex.h
#pragma once
#include <iosfwd>  // std::ostream

namespace ns1 {
class complex {
    double re_{}, im_{};
    friend std::ostream& operator<<(std::ostream&, const complex&);
public:
    // ...
};
// Optional: make it visible to ordinary lookup too
std::ostream& operator<<(std::ostream&, const complex&);
} // namespace ns1
// complex.cpp
#include "complex.h"
#include <ostream>

namespace ns1 {
std::ostream& operator<<(std::ostream& os, complex const& z) {
    // format however you like...
    return os;
}
} // namespace ns1

Two quick refinements:

  • Avoid using namespace std; in headers; qualify names instead. This prevents surprises for every file that includes your header. C++ Core Guidelines SF.7.
  • Consider renaming complex (or keep it in ns1) to avoid confusion with std::complex if anyone adds using namespace std in a .cpp later.

This explains why your move to three files caused access errors and how to prevent them going forward.

Recommended Answers

All 4 Replies

in ur .h file u need to do something like this:

class Complex
{
	friend ostream &operator<<( ostream &, const Complex & );
	friend istream &operator>>( istream &, Complex & );
public:
//ur stuff
private:
//ur stuff
};

u should declare the input and ouput operators as friends of the class, not only one

I don't see how that would make any difference, and upon trying it, it doesn't.

The source (.cppp) definition must be placed inside the namespace block.

#include<iostream>
#include<cstdlib>
#include<cmath>
#include "head.h"

using namespace std;

namespace ns1 {

double complex::getreal() const {return re;}
double complex::getimag() const {return im;}
double complex::getmod() {return sqrt(re*re + im*im);}
double complex::getmod2() const {return (re*re+ im*im);}
complex complex::getconj() const {complex temp(re,im*-1);return temp;}

complex complex::operator+ (const complex &z) const {complex temp(re+z.getreal(),im+z.getimag());return temp;}

ostream & operator<<(ostream &os, const complex &z)
{
	if(z.im==0)	{os<< z.re; return os;}
	else{
		if(z.im>0)	{os<< z.re << "+"<< z.im << "i"; return os;}
		else		{os<< z.re << z.im << "i"; return os;}
		}
 }
};

OR you may qualify each definition separately.

......
double ns1::complex::getreal() const {return re;}
double ns1::complex::getimag() const {return im;}
double ns1::complex::getmod() {return sqrt(re*re + im*im);}
double ns1::complex::getmod2() const {return (re*re+ im*im);}
ns1::complex ns1::complex::getconj() const {complex temp(re,im*-1);return temp;}

ns1::complex ns1::complex::operator+ (const complex &z) const {complex temp(re+z.getreal(),im+z.getimag());return temp;}

ostream & ns1::operator<<(ostream &os, const complex &z)
{
	if(z.im==0)	{os<< z.re; return os;}
	else{
		if(z.im>0)	{os<< z.re << "+"<< z.im << "i"; return os;}
		else		{os<< z.re << z.im << "i"; return os;}
		}
}

Thanks! That was all it needed!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.