友元:解决运算符重载参数顺序问题

友元:解决运算符重载顺序问题

目录

  • 友元:解决运算符重载顺序问题
    • 运算符重载
      • 重载函数
    • 友元
      • 友元函数
      • 友元函数对运算符重载
      • 重载<<运算符
        • 友元函数返回值类型:void
        • 友元函数返回值类型:ostream
    • 模板类重的友元函数重载运算符

运算符重载

代码举例:复数类的加号重载

#include
#include
using namespace std;
class complex{
    private:
    int real,imag;
    public:
    complex(int r=0,int i=0):real(r),imag(i){}
    int realshow(){return real;}
    int imagshow(){return imag;}
    void printc(){
      cout<<real<<'+'<<imag<<'i'<<endl;  
    }
    complex operator+(const complex &);
    friend complex operator+(int);
    complex Sum(const complex &);
    complex operator+(int);
    bool operator==(complex);
    complex operator++();
    complex operator++(int);
    ~complex(){};
}; 
complex complex::operator++(){
    this->real+=1;
    return *this;
  }
complex complex::operator++(int){
    this->real+=1;
    return *this;
  }
bool complex::operator==(complex c){
    if(this->real==c.real && this->imag==c.imag) return true;
    else return false;
}

重载函数

complex complex::operator+(complex &c){
    complex temp; 
    temp.real=this->real+c.real;
    temp.imag=this->imag+c.imag;
    return temp;
 }
 complex complex::operator+(conplex &c){
    complex temp; 
    temp.real=this->real+c.real;
    temp.imag=this->imag+c.imag;
    return temp;
 }
 complex complex::Sum(int c){
    complex temp; 
    temp.real+=c;
    temp.imag+=this->imag;
    return temp;
 }
 complex complex::operator+(int c){
    complex temp; 
    temp.real+=c;
    temp.imag+=this->imag;
    return temp;
 }

测试:

int main(){
    complex c1(1,2),c2(5,3);
    complex c3,c4,c5;
    c3=c1+c2;
    c4=c1.Sum(c2);
    c5=c1.operator+(c2);
     (++c1).printc();
    c3.printc();
    system("pause"
    );
    return 0;
    
}

由测试函数可知,将Sum()的函数名替换为operator+就是运算符的重载,第一个运算数通过this指针隐式调用,a+b实质上是
a.operator+(b),要注意的是,形参使用的是运算数的引用传递,使用const,避免修改数据,节约值传递的时间,但是返回值不能使用引用传递,对局部变量使用引用传递,变量生命结束后,找不到他的值。

友元

运算符重载也有一个问题,例如operator+(int),复数与实数相加,只能复数在前,因为重载的加号是复数类的成员函数,这要求我们对其进行修改使实数在前也能进行加法,使用友元可以有效解决这一问题。

友元函数

关于友元,包含友元类、友元函数,友元类是通过在类中添加friend class another_classname的形式,使其他类能够访问其私有成员,虽然这一定程度上破坏了类的封装性,但在一些情况下可以有效节约代码量。这里着重提友元函数

在面向对象编程中,友元函数(friend function)是一个指定类(class)的“朋友”,该函数被允许访问该类中private、protected、public的数据成员。普通的函数并不能访问这些数据,然而宣告一个函数成为一个类的友元函数则被允许访问这些数据。

友元函数的声明可以放在类声明的任何地方,不受访问限定关键字private、protected、public的限制。

A类的成员函数作为B类的友元函数时,必须先定义A类,而不仅仅是声明它。

注意:将其他类的成员函数申明为本类的友元函数后,该友元函数并不能变成本类的成员函数。也就是说,朋友并不能变成家人。

友元函数对运算符重载

我们通过友元函数来实现非成员函数对+的重载,输入两个运算数变量,(成员函数不能显式地传递自己)

class complex{
    friend complex operator+(complex &c,int x);
    }
complex operator+(complex &c,int x){
    complex temp; 
    temp.real=c.real+x;
    temp.imag=c.imag;
    return temp;
}

重载<<运算符

<<如果使用正常的(类内函数)重载方式,有两个参数,一个是隐式的复数类变量,另一个是ostream的输出函数ostream &cout,那么应该是c<

友元函数返回值类型:void

class complex{
    friend void operator<<(ostream &os,const complex &c);
    }
void operator<<(ostream &os,const complex &c){
    os<<c.real<<'+'<<c.imag<<'i'<<endl;  
}

operator<<是complex的友元,它访问了complex的私有成员,但它并非ostream的友元,它将os这个对象作为整体使用,并未访问ostream的私有与保护成员,c应该为引用传递,访问的应该是c本身而非他的复制

但是void返回会带来一个问题,<<要求左边是ostream类型的对象,上面代码中的友元会使下面语句出错,不能连续输出

cout<<c<<1<<endl; //出错

友元函数返回值类型:ostream

class complex{
    friend ostream &operator<<(ostream &os,const complex &c);
    }
 ostream &operator<<(ostream &os,const complex &c){
    os<<c.real<<'+'<<c.imag<<'i'<<endl;  
    return os;
}

返回值为os的引用,仍为ostream类型的对象

模板类重的友元函数重载运算符

使用模板类与实例类有区别,一定要注意的两个点
1。友元函数一定要在类之前声明,否则找不到函数,会报错;原因是在编译时,模板类生成两次,一次是类头,另一次是实例化,而友元函数是全局函数,使第一次生成时找不到函数,因此需要在类描述前进行生命
2. 友元函数在类中声明时,因为在类之前已经模板声明了一次,因此在类中的声明需要在()前加**< T >**,否则也会报错,实现时不需要加

以顺序栈的<<重载为例,部分代码如下

#include 
#include 
using namespace std;
const int stackincrease = 20;
template <class T> class SeqStack;
**template <class T> ostream &operator<<(ostream &os, const SeqStack<T> &s);  //1.友元函数一定要提前声明**
template <class T> class SeqStack {
  private:
    T *data;
    int top; //栈顶指针
    int maxsize;
    void overflowstack(); //溢出处理
  public:
    SeqStack(int sz = 50) : top(-1), maxsize(sz) {
        data = new T[maxsize];
        assert(data != NULL); // assert函数当判断为假的时候输出
    }
    ~SeqStack() { delete[] data; }
    void Push(const T &x);   //压栈
    bool Pop(T &x);          //出栈 ,栈顶元素用x返回
    bool getTop(T &x) const; //得到栈顶元素,x返回
    bool Isempty() const { return (top == -1) ? true : false; }         //判空
    bool Isfull() const { return (top + 1 == maxsize) ? true : false; } //判满
    int getsize() const { return top + 1; } //栈元素数
    void makeempty() { top = -1; }          //清空栈
    **friend ostream &operator<<<T>(ostream &os, const SeqStack<T> &s); //2.重载输出  一定要加否则就不是模板函数**
};

template <class T> ostream &operator<<(ostream &os, const SeqStack<T> &s) {
    for (int i = 0; i <= s.top; i++)
        os << s.data[i] << ' ';
    return os;
}

你可能感兴趣的:(C++,c++,类,多态)