程序员

运算符重载与友元函数

2020-12-14  本文已影响0人  骑猪满天飞

运算符重载

C++允许将运算符重载到用户定义的类型,例如,使用+将两个类对象相加。

重载运算符要使用运算符函数:

operatorop(argument-list);
使用方法:
operator+() //重载+运算符

这里给出一个简单的复数类,并重载了运算符,实现复数的加、减、乘运算

假设a=(A,Bi),c=(C,Di) 复数的运算法则:

class Complex
{
private:
    double real;
    double imag;
public:
    Complex();
    Complex(double r, double i);
    Complex operator+(const Complex &a) const;
    Complex operator-(const Complex &a) const;
    Complex operator*(const Complex &a) const;
    Complex operator*(double x) const;
};
Complex Complex::operator+(const Complex &a) const{ //第二个const是为了确保this所指对象不被修改
    Complex temp;
    temp.real = this->real + a.real;
    temp.imag = this->imag + a.imag;
    return temp;
}

Complex Complex::operator-(const Complex &a) const{
    Complex temp;
    temp.real = this->real - a.real;
    temp.imag = this->imag - a.imag;
    return temp;
}

Complex Complex::operator*(const Complex &a) const{
    Complex temp;
    temp.real = this->real * a.real - this->imag * a.imag;
    temp.imag = this->real * a.imag + this->imag * a.real;
    return temp;
}

Complex Complex::operator*(double x) const {
    Complex temp;
    temp.real = this->real * x;
    temp.imag = this->imag * x;
    return temp;
}

如果result,a,c是Complex类的三个对象,则计算复数a和c的和,可以编写等式:result = a + c

编译器将上述语句转化为result = a.operator+(c),因此如果还有一个d对象,result = a + c + d也是成立的,此语句将被编译器转化为result = a.operator+(c.operator+(d))

重载限制

  1. 重载后的运算符必须有一个操作数为用户定义的数据类型,这是为了防止用户为标准类型重载运算符,如将int类型相加的运算符+重载,将出现问题。
  2. 使用运算符时不能违反运算符原来的语法规则。例如,不能将求模运算符(%)重载成使用一个操作数
  3. 不能创建新的运算符

友元函数

C++严格控制类对象的私有数据访问,外部只能通过公有的类方法来访问私有数据。然而在特定情况下需要外部函数来访问类的私有数据,这种情况下,C++提供了另一种访问形式:友元。

通过让函数成为类的友元,可以使得该函数与类的成员方法有相同的权限。例如,Complex类提供了运算符 * 的重载,实现复数与实数相乘:Complex operator*(double x) const;使用此重载,需要第一个操作数为类对象。

如语句:

result = a * 2

将被转化为下面的成员函数调用:

result = a.operator*(2)

但是当表达式写成result = 2 * a 时将出错,因为2不是Complex类对象,没有operator*()方法。

为了解决此问题,应当编写一个原型如下的非成员函数来重载*:

Complex operator*(const double x, const Complex a);

但是非成员函数无法访问类的私有数据,所以需将此函数申明为Complex的友元函数,操作如下:

class Complex
{
private:
    double real;
    double imag;
public:
    ```
    friend Complex operator*(const double x, const Complex a); //关键字friend表示类的友元函数
    
};

Complex operator*(const double x, const Complex a) { //函数定义时不需要friend关键字
    Complex temp;
    temp.real = a.real * x; //非友元函数无法访问a.real 与 a.imag
    temp.imag = a.imag * x;
    return temp;
}

有了上述声明和定义以后下面语句

result = 2 * a

将被转化为如下语句,从而调用定义的友元函数:

result = operator(2 , a)

常用友元:重载<<、>>运算符

为了输出类对象的内容,我们可以重载<<运算符:

class Complex
{
private:
    double real;
    double imag;
public:
    ```
    void operator<<(std::ostream& os) const;
    
};

void Complex::operator<<(std::ostream& os) const {
    os << "(" << real << "," << imag << "i)";
    
}

但是上述重载存在几个问题:

为解决此问题需要用到友元函数,调换参数顺序修改如下:

class Complex
{
private:
    double real;
    double imag;
public:
    ```
    friend void operator<<(std::ostream& os, const Complex &a);
    
};

void operator<<(std::ostream& os, const Complex& a) {
    os << "(" << a.real << "," << a.imag << "i)";
}

这样输出的表达式就变成cout << c

正确重载<<的代码如下:

class Complex
{
private:
    double real;
    double imag;
public:
    ```
    friend std::ostream& operator<<(std::ostream& os, const Complex &a);
    
};

std::ostream& operator<<(std::ostream& os, const Complex& a) {
    os << "(" << a.real << "," << a.imag << "i)";
    return os;
}

同理运算符>>的重载如下:

class Complex
{
private:
    double real;
    double imag;
public:
    ```
    friend std::ostream& operator<<(std::ostream& os, const Complex &a);
    friend std::istream& operator>>(std::istream& is, Complex &a);
    
};

std::ostream& operator<<(std::ostream& os, const Complex& a) {
    os << "(" << a.real << "," << a.imag << "i)";
    return os;
}

std::istream& operator>>(std::istream& is, Complex& a) {
    std::cout << "Input real part of number :";
    is >> a.real;
    std::cout << "Input imaginary part of number :";
    is >> a.imag;
    return is;
}

完整代码与测试

complex0.h

#include <iostream>
class Complex
{
private:
    double real;
    double imag;
public:
    Complex();
    Complex(double r, double i);
    Complex operator+(const Complex &a) const;
    Complex operator-(const Complex &a) const;
    Complex operator*(const Complex &a) const;
    Complex operator*(double x) const;
    Complex operator~() const;
    
    friend Complex operator*(const double x, const Complex a);
    friend std::ostream& operator<<(std::ostream& os, const Complex &a);
    friend std::istream& operator>>(std::istream& is, Complex &a);


};

complex0.cpp
    
#include <iostream>
#include "complex0.h"


Complex::Complex() {
    real = 0.0;
    imag = 0.0;
}
Complex::Complex(double r, double i) {
    real = r;
    imag = i;
}

Complex Complex::operator+(const Complex &a) const{
    Complex temp;
    temp.real = this->real + a.real;
    temp.imag = this->imag + a.imag;
    return temp;
}

Complex Complex::operator-(const Complex &a) const{
    Complex temp;
    temp.real = this->real - a.real;
    temp.imag = this->imag - a.imag;
    return temp;
}

Complex Complex::operator*(const Complex &a) const{
    Complex temp;
    temp.real = this->real * a.real - this->imag * a.imag;
    temp.imag = this->real * a.imag + this->imag * a.real;
    return temp;
}

Complex Complex::operator*(double x) const {
    Complex temp;
    temp.real = this->real * x;
    temp.imag = this->imag * x;
    return temp;
}

Complex Complex::operator~() const{
    Complex temp;
    temp.real = this->real;
    temp.imag = -this->imag;
    return temp;
}

Complex operator*(const double x, const Complex a) {
    Complex temp;
    temp = a * x;
    return temp;
}

std::ostream& operator<<(std::ostream& os, const Complex& a) {
    os << "(" << a.real << "," << a.imag << "i)";
    return os;
}

std::istream& operator>>(std::istream& is, Complex& a) {
    std::cout << "Input real part of number :";
    is >> a.real;
    std::cout << "Input imaginary part of number :";
    is >> a.imag;
    return is;
}
main.cpp

#include <iostream>
#include "complex0.h" 
using namespace std;

int main() {

    Complex a(3.0, 4.0);
    Complex c;
    cout << "Enter a complex (q to quit):" << endl;
    while (cin >> c) {
        
        cout << "c is" << c << endl;
        cout << "complex conjugate is " << ~c << endl;
        cout << "a is " << a << endl;
        cout << "a + c is " << a.operator+(c) << endl;
        cout << "a - c is " << a - c << endl;
        cout << "a * c is " << a * c << endl;
        cout << "2 * a  is " << 2 * a << endl;
        cout << "a * 2  is " << a * 2 << endl;
        cout << "Enter a complex (q to quit):" << endl;
    }   
}
result.png
上一篇 下一篇

猜你喜欢

热点阅读