C++快速入门6

76 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

我们想要将student类型,也就是自定义类型放在<<后面进行输出,这时候就要运算符重载。

<<完整函数名是operator<< ,既然是函数就能重载

#include<iostream>

using namespace std;

struct student
{
    string name;
    double score;
public:
    student(string name, double score){
        this->name = name;
        this->score = score;
    }
    void print(){
        cout << name << ' ' << score << endl;
    }
    string getName(){
        return name;
    }
    double getScore(){
        return score;
    }
    void setName(string name){
        this->name = name;
    }
    void setScore(double score){
        this->score = score;
    }
};

ostream& operator<<(ostream& o, student s){
    cout << s.name << " " << s.score << endl;
    return o;
}

int main(){
    student s1("aa", 65);
    cout << s1;
    return 0;
}

asdasd

在这里使用<<时实际是operator<<(cout, s1)

最后返回的是ostream,因为使用时我们会有连续使用的情况,如:cout << s1 << s2 << endl;注意返回的是引用类型。

如果要改成class就出问题了,因为属性是私有的,而输出类型运算符是外部函数

想要使用,有以下方法:

  1. 使用公开的函数访问cout << s.getName() << " " << s.getScore() << endl;
  2. 设置这个函数为友元函数,那么它就是这个类的朋友,就能访问属性

我们也可以对输入运算符重载,但为了改变对象的值,必须定义为引用类型,不然改变的只是形参这个局部变量。

friend istream &operator>>(istream &i, student &s);

我们再定义一个下标运算符,它和刚刚的两个就不一样,必须作为成员函数。

#include<iostream>

using namespace std;

class Point{
private:
    double x;
    double y;
public:
    Point(double x, double y){
        this->x = x;
        this->y = y;
    }
    double operator[](int i){
        if(i ==0){
            return x;
        }
        else if (i==1){
            return y;
        }
        else{
            throw "越界";
        }
        
    }
};

int main(){
    Point p(1, 2);
    cout << p[0];
    return 0;
}

但这里不能对属性进行修改

可以进行重载,定义两个函数

double operator[](int i) const{
        if(i ==0){
            return x;
        }
        else if (i==1){
            return y;
        }
        else{
            throw "越界";
        }
    }
    double& operator[](int i){
        if(i ==0){
            return x;
        }
        else if (i==1){
            return y;
        }
        else{
            throw "越界";
        }
    }

为了实现重载,第一个后面可以加上const,这样两个函数的签名就不一样,加上const代表该函数不会对数据进行更改

对于+我们也可以重载,有两种形式

外部函数:

Point operator+(const Point p, const Point q){
    return Point(p[0] + q[0], p[1] + q[1]);
}

本质上是operator+(p, q)

成员函数:

Point operator+(const Point q){
    return Point(this->x + q[0], this->y + q[1]);
}

本质上是p.operator+(q)

有的运算符只能所谓成员函数重载,如[]

有的运算符只能作为外部函数重载,如<<

有的运算符既可以作为外部函数,也可以作为成员函数重载,如+

规则

  1. 并不是所有的运算符都可以重载。能够重载的运算符包括:
    + - * / % ^ & | ~ ! = < > += -= = /= %= ^= &= |= << >> <<= >>= == != <= >= && || ++ -- , -> -> () [] new new[] delete delete[]

    上述运算符中,[]是下标运算符,()是函数调用运算符。自增自减运算符的前置和后置形式都可以重载。长度运算符sizeof、条件运算符: ?、成员选择符.和域解析运算符::不能被重载。

  2. 重载不能改变运算符的优先级和结合性。

  3. 重载不会改变运算符的用法,原有有几个操作数、操作数在左边还是在右边,这些都不会改变。例如~号右边只有一个操作数,+号总是出现在两个操作数之间,重载后也必须如此。

  4. 运算符重载函数不能有默认的参数,否则就改变了运算符操作数的个数,这显然是错误的。

  5. 运算符重载函数既可以作为类的成员函数,也可以作为全局函数。
    将运算符重载函数作为类的成员函数时,二元运算符的参数只有一个,一元运算符不需要参数。之所以少一个参数,是因为这个参数是隐含的。