【C++学习总结2-6】类和对象(封装)—— 重载

1. 函数重载

【C++学习总结2-6】类和对象(封装)—— 重载
编译器是没有办法通过返回值来确认调用的是哪个函数的。

代码:

#include<iostream>
using namespace std;

int func(int x) {
    return 2 * x;
}

double func(double x) {
    return x * x;
}

int func(int x, int y) {
    return x * y;
}

int main() {
    cout << func(2) << endl;//func(int)
    cout << func(2.3) << endl; // func(double)
    cout << func(2, 4) << endl; // func(int, int)
    return 0;
}

冲突形式:参数有默认值
【C++学习总结2-6】类和对象(封装)—— 重载
针对这种情况,可以将两个函数进行合并:

#include<iostream>
using namespace std;
//两种调用形式
//func(int)
//func(int, int)
int func(int x, int y = 10) {
    return x * y;
}
double func(double x) {
    return x * x;
}

int main() {
    cout << func(2) << endl;//func(int)
    cout << func(2.3) << endl; // func(double)
    cout << func(2, 4) << endl; // func(int, int)
    return 0;
}

无法通过返回值来做函数重载形式的区分:
【C++学习总结2-6】类和对象(封装)—— 重载

2. 重载的意义

【C++学习总结2-6】类和对象(封装)—— 重载

3. 友元

类外的一个函数 想要访问类内部成员,需要将该函数声明成类的一个友元函数。

形式如下:

class A {
	private :
    	int a;
    	int b;
    public :
    	A() : a(0), b(0) {}
    	A(int a, int b): a(a), b(b) {}
    	A(const A &obj): a(obj.a), b(obj.b) {}
    	friend A add(const A &obj1, const A &obj2);
};

A add(const A &obj1, const A &obj2) {
    A ret(0, 0);
    ret.a = obj1.a + obj2.a;
    ret.b = obj1.b + obj2.b;
    return ret;
}

实例:

#include<iostream>
using namespace std;

class Data {
public:
    Data() {}
    Data(int x, int y) : x(x), y(y) {
        cout << "Data : " << this << endl;
    }
    friend ostream &operator<<(ostream &out, const Data &d);
private:
    int x, y;
};

ostream &operator<<(ostream &out, const Data &d) {
    //访问Data的私有属性,需要在Data类中将该函数声明为friend
    out << d.x << " " << d.y;
    return out;
}

int main() {
    Data d(10, 9);
    //对<< 进行重载
    cout << d << endl;
    return 0;
}

友元函数本质上是一个类外部的函数,声明为友元函数后虽然还是类外的函数,但是可以访问类内部的私有属性。

4. 运算符重载(非成员)

【C++学习总结2-6】类和对象(封装)—— 重载

4.1 什么符号能被重载?

【C++学习总结2-6】类和对象(封装)—— 重载

sizeof也是运算符,也无法被重载,但是通常不被认为是运算符,而是函数。

注意:newdelete是运算符,malloc是函数。

4.2 类外重载

#include<iostream>
using namespace std;

class Point {
public:
    Point();
    Point(int x, int y);

private:
    friend Point operator+(const Point &a, const Point &b);
    friend ostream &operator<<(ostream &out, const Point &p);
    int x, y;
};

//委托构造:调用了Point(int, int)构造函数进行构造
Point::Point() : Point(0, 0) {}
Point::Point(int x, int y) : x(x), y(y) {}

//类外重载+号
//第一个参数代表+号左边的变量,第二个代表+号右边的变量
Point operator+(const Point &a, const Point &b) {
    Point c(a.x + b.x, a.y + b.y);
    return c;
}

//重载<<运算符
//第一个参数代表<<运算符左边的变量,第二个代表<<运算符右边的变量
ostream &operator<<(ostream &out, const Point &p) {
    out << "(" << p.x << ", " << p.y << ")";
    return out;
}

int main() {
    Point a(3, 4);
    Point b(7, 9);
    Point c = a + b;
    cout << a << endl;
    cout << b << endl;
    cout << c << endl;
    return 0;
}
//输出结果:
//(3, 4)
//(7, 9)
//(10, 13)

问:什么是委托构造

答:

Point::Point() : x(0), y(0) {}
Point::Point(int x, int y) : x(x), y(y) {}

代码中的第2行是分别对 xy 进行赋值,第1行是将 xy 都赋值为0,所以1行可以委托2行进行构造:

Point::Point() : Point(0, 0) {}
Point::Point(int x, int y) : x(x), y(y) {}

4.3 类内重载

#include<iostream>
using namespace std;

class Point {
public:
    Point();
    Point(int x, int y);
    //类内重载运算符+,只需要传入一个参数
    //因为this指针指向的对象代表了+左边的参数,而传入的参数a代表+右边的参数
    Point operator+(const Point &a);
private:
    friend Point operator+(const Point &a, const Point &b);
    friend ostream &operator<<(ostream &out, const Point &p);
    int x, y;
};

Point::Point() : Point(0, 0) {}
Point::Point(int x, int y) : x(x), y(y) {}

//类内重载+
Point Point::operator+(const Point &a) {
    cout << "inner operator+" << endl;
    Point c(x + a.x, y + a.y);
    return c;
}

//类外重载+
Point operator+(const Point &a, const Point &b) {
    cout << "outer operator+" << endl;
    Point c(a.x + b.x, a.y + b.y);
    return c;
}

ostream &operator<<(ostream &out, const Point &p) {
    out << "(" << p.x << ", " << p.y << ")";
    return out;
}

int main() {
    Point a(3, 4);
    Point b(7, 9);
    Point c = a + b;
    cout << a << endl;
    cout << b << endl;
    cout << c << endl;
    return 0;
}

类外重载和类内重载同时存在不会冲突,因为类内重载的优先级更高,同时存在的时候会调用类内重载。

4.4 重载成员函数的原则

  • 赋值(=)、下标([])、调用(())、成员访问(->) 运算符必须重载为成员函数
  • 复合赋值运算符一般重载为成员函数
  • 改变对象运算状态的运算符和类型密切相关的运算符,一般重载为成员函数,如:自增等
  • 具有对称性的运算符可能转换任意一端的对象,通常重载为非成员函数,如:相等,关系和位运算

4.5 重载+=运算符

#include<iostream>
using namespace std;

class Point {
public:
    Point();
    Point(int x, int y);
    //类内重载运算符+,只需要传入一个参数
    //因为this指针指向的对象代表了+左边的参数,而传入的参数a代表+右边的参数
    Point operator+(const Point &a);
    //重载+=运算符
    Point &operator+=(int);
private:
    friend Point operator+(const Point &a, const Point &b);
    friend ostream &operator<<(ostream &out, const Point &p);
    int x, y;
};

Point::Point() : Point(0, 0) {}
Point::Point(int x, int y) : x(x), y(y) {}

Point &Point::operator+=(int n) {
    x += n, y += n;
    return *this;
}

//类内重载+
Point Point::operator+(const Point &a) {
    cout << "inner operator+" << endl;
    Point c(x + a.x, y + a.y);
    return c;
}

//类外重载+
Point operator+(const Point &a, const Point &b) {
    cout << "outer operator+" << endl;
    Point c(a.x + b.x, a.y + b.y);
    return c;
}

ostream &operator<<(ostream &out, const Point &p) {
    out << "(" << p.x << ", " << p.y << ")";
    return out;
}

int main() {
    Point a(3, 4);
    Point b(7, 9);
    Point c = a + b;
    cout << a << endl;
    cout << b << endl;
    cout << c << endl;

    a += 2; //给a的x和y各+2
    cout << a << endl;
    return 0;
}

注意这两行代码:

Point operator+(const Point &a);
Point &operator+=(int);

为什么重载 += 运算符返回的是引用?重载 + 运算符返回的是一个新的值?

a += 2; 是作用在 a 上。

从逻辑上来讲,这个表达式返回的还是 a 的值,所以返回引用;

从功能上来讲,如果连续加 (a += 2) += 2; 则必须返回引用,只有前一个 += 表达式返回的是引用,后一个 += 才会继续作用于对象 a 上。

运算符的返回值是任意的,并没有规定一定要返回引用。

4.6 [] 运算符的重载

[] 重载出来的对象叫做==数组对象==;

[]只支持==类内重载==

#include<iostream>
using namespace std;

class Point {
public:
    Point();
    Point(int x, int y);
    //类内重载运算符+,只需要传入一个参数
    //因为this指针指向的对象代表了+左边的参数,而传入的参数a代表+右边的参数
    Point operator+(const Point &a);
    //重载+=运算符
    Point &operator+=(int);
    int operator[](string s);
private:
    friend Point operator+(const Point &a, const Point &b);
    friend ostream &operator<<(ostream &out, const Point &p);
    int x, y;
};

Point::Point() : Point(0, 0) {}
Point::Point(int x, int y) : x(x), y(y) {}
int Point::operator[](string s) {
    if (s == "x") return x;
    if (s == "y") return y;
    return 0;
}
Point &Point::operator+=(int n) {
    x += n, y += n;
    return *this;
}

//类内重载+
Point Point::operator+(const Point &a) {
    cout << "inner operator+" << endl;
    Point c(x + a.x, y + a.y);
    return c;
}

//类外重载+
Point operator+(const Point &a, const Point &b) {
    cout << "outer operator+" << endl;
    Point c(a.x + b.x, a.y + b.y);
    return c;
}

ostream &operator<<(ostream &out, const Point &p) {
    out << "(" << p.x << ", " << p.y << ")";
    return out;
}

int main() {
    Point a(3, 4);
    Point b(7, 9);
    cout << a["x"] << endl;
    cout << a["y"] << endl;
    Point c = a + b;
    cout << a << endl;
    cout << b << endl;
    cout << c << endl;

    a += 2; //给a的x和y各+2
    cout << a << endl;
    return 0;
}

因为 Point 类重载了 [] 运算符,所以所有 Point 类的对象都支持 [] 运算符,因此可以在 a 对象后面加上 [] 运算符。

a 对象的外在表现像一个数组,但是它的本质还是一个对象。所以将重载了 [] 运算符的类产生的对象,叫做数组对象,就是外在表现是一个数组,但是本质上还是一个对象。

4.7 () 运算符的重载

()重载出来的对象叫做函数对象,也叫==仿函数==;

#include<iostream>
using namespace std;

class ADD {
public :
    ADD(int c) : c(c) {}
    int operator()(int a, int b) {
        return a + b + c;
    }
private :
    int c;
};

int main() {
    ADD add(5);
    cout << add(6, 7) << endl; //输出18
    return 0;
}

add对象表现得像个函数,但是本质是个对象,所以叫做函数对象,也叫做可调用对象,也称仿函数

4.8 -> 运算符的重载

-> (间接引用)重载出来的对象叫做 指针对象

#include<iostream>
using namespace std;

class Point {
public :
    Point();
    Point(int x, int y);
    //类内重载运算符+,只需要传入一个参数
    //因为this指针指向的对象代表了+左边的参数,而传入的参数a代表+右边的参数
    Point operator+(const Point &a);
    //重载+=运算符
    Point &operator+=(int);
    //重载[]运算符
    int operator[](string s);
    int getX() { return x; }
    int getY() { return y; }
private :
    friend Point operator+(const Point &a, const Point &b);
    friend ostream &operator<<(ostream &out, const Point &p);
    int x, y;
};

class PPoint {
public :
    PPoint(Point *p) : p(p) {}
    Point *operator->() { return p; } //->运算符重载通常返回指针
private:
    Point *p;
};

Point::Point() : Point(0, 0) {}
Point::Point(int x, int y) : x(x), y(y) {}
int Point::operator[](string s) {
    if (s == "x") return x;
    if (s == "y") return y;
    return 0;
}
Point &Point::operator+=(int n) {
    x += n, y += n;
    return *this;
}

//类内重载+
Point Point::operator+(const Point &a) {
    cout << "inner operator+" << endl;
    Point c(x + a.x, y + a.y);
    return c;
}

//类外重载+
Point operator+(const Point &a, const Point &b) {
    cout << "outer operator+" << endl;
    Point c(a.x + b.x, a.y + b.y);
    return c;
}

ostream &operator<<(ostream &out, const Point &p) {
    out << "(" << p.x << ", " << p.y << ")";
    return out;
}

int main() {
    Point a(3, 4);
    Point b(7, 9);
    cout << a["x"] << endl;
    cout << a["y"] << endl;
    Point c = a + b;
    cout << a << endl;
    cout << b << endl;
    cout << c << endl;

    a += 2; //给a的x和y各+2
    cout << a << endl;

    PPoint p = &a; //调用了转换构造函数
    cout << p->getX() << " " << p->getY() << endl;
    return 0;
}

对象 p 表现得像个指针,但是本质上是个对象,所以叫做对象指针

4.9 实现智能指针对象

智能指针前导知识

智能指针shared_ptr定义在头文件<memory>中。

产生了内存泄漏的代码:

#include <iostream>
#include <memory>
using namespace std;

class A {
public :
    A() {
        cout << "default constructor" << endl;
    }
    ~A() {
        cout << "destructor" << endl;
    }
};

int main() {
    A *p1 = new A();
    p1 = nullptr;
    return 0;
}

因为对象 p1 没有被销毁,系统中任何一个存储数据的地方都不知道对象的地址是什么,即一片存储区是属于当前进程的,但是当前进程永远找不到这片存储区在哪儿。

使用普通指针,只有构造的过程,没有析构的过程,所以发生了内存泄漏。

但是使用智能指针,不会产生内存泄漏:

#include <iostream>
#include <memory>
using namespace std;

class A {
public :
    A() {
        cout << "default constructor" << endl;
    }
    ~A() {
        cout << "destructor" << endl;
    }
};

int main() {
    A *p1 = new A();
    p1 = nullptr;

    //p2就是智能指针对象
    shared_ptr<A> p2(new A());
    p2 = nullptr; //自动析构

    return 0;
}

运行结果:

default constructor
default constructor
destructor

智能指针的智能之处:没有指针指向当前对象时,智能指针会将相关对象析构。

智能指针的原理:内部有个 引用计数,会记录指向当前对象的智能指针的数量。

#include <iostream>
#include <memory>
using namespace std;

class A {
public :
    A() {
        cout << "default constructor" << endl;
    }
    ~A() {
        cout << "destructor" << endl;
    }
};

int main() {
    A *p1 = new A();
    p1 = nullptr;

    //p2就是智能指针对象
    shared_ptr<A> p2(new A());
    //输出引用计数:p2所指向的对象有多少个指针指向它
    cout << p2.use_count() << endl; // 1,只有p2
    shared_ptr<A> p3 = p2;
    cout << p2.use_count() << endl; // 2,p2和p3
    p2 = nullptr; //自动析构
    cout << p3.use_count() << endl; // 1,只有p3

    return 0;
}

运行结果:

default constructor
default constructor
1
2
1
destructor

之所以最后调用 destructor,是因为在 main 函数执行完毕后,p3 对象被自动回收,指向当前对象的智能指针的数量就变成了0,引用计数变为了0,这时候对象就被智能指针析构了。

智能指针之所以表现得像个指针,是因为它重载了 -> 运算符,还重载了 * 运算符:

#include <iostream>
#include <memory>
using namespace std;

class A {
public :
    A() {
        cout << "default constructor" << endl;
    }
    int x, y;
    ~A() {
        cout << "destructor" << endl;
    }
};

int main() {
    A *p1 = new A();
    p1 = nullptr;

    //p2就是智能指针对象
    shared_ptr<A> p2(new A());
    //输出引用计数:p2所指向的对象有多少个指针指向它
    cout << p2.use_count() << endl; // 1
    shared_ptr<A> p3 = p2;
    p2->x = 123;
    p2->y = 456;
    (*p2).x = 456;
    cout << p2.use_count() << endl; // 2
    p2 = nullptr; //自动析构
    cout << p3.use_count() << endl; // 1

    return 0;
}

实现智能指针对象

#include <iostream>
#include <memory>
using namespace std;

namespace haizei {
class A {
public :
    A() {
        cout << "default constructor" << endl;
    }
    int x, y;
    ~A() {
        cout << "destructor" << endl;
    }
};
class shared_ptr {
public :
    shared_ptr();
    shared_ptr(A *);
    shared_ptr(const shared_ptr &);
    int use_count();
    A *operator->();
    A &operator*();
    //赋值运算符之所以要返回当前对象的引用,是为了支持连等的操作
    shared_ptr &operator=(const shared_ptr &);
    ~shared_ptr();
private :
    int *cnt; //引用计数
    A *obj;
};

shared_ptr::shared_ptr() : obj(nullptr), cnt(nullptr) {}

shared_ptr::shared_ptr(A *obj) : obj(obj), cnt(new int(1)) {}

shared_ptr::shared_ptr(const shared_ptr &p) : obj(p.obj), cnt(p.cnt) { *p.cnt += 1; }

int shared_ptr::use_count() { return cnt ? *cnt : 0; }

A *shared_ptr::operator->() { return obj; }

A &shared_ptr::operator*() { return *obj; }

shared_ptr::~shared_ptr() {
    if (cnt != nullptr) {
        *cnt -= 1;
        if (*cnt == 0) {
            delete obj;
            delete cnt;
        }
        obj = nullptr;
        cnt = nullptr;
    }
}

shared_ptr &shared_ptr::operator=(const shared_ptr &p) {
    //判断是否指向同一个对象
    if (this->obj != p.obj) {
        if (this->cnt != nullptr) {
            *(this->cnt) -= 1;
            if (*(this->cnt) == 0) {
                delete this->obj;
                delete this->cnt;
            }
        }
        this->obj = p.obj;
        this->cnt = p.cnt;
        if (this->cnt != nullptr) {
            *(this->cnt) += 1;
        }
    }
    return *this;
}

} // end of haizei


int main() {
    haizei::A *p1 = new haizei::A();
    p1 = nullptr;

    //p2就是智能指针对象
    haizei::shared_ptr p2(new haizei::A());
    cout << p2.use_count() << endl; // 1
    haizei::shared_ptr p3 = p2;
    p2->x = 123; p2->y = 456;
    (*p2).x = 456;
    cout << p2.use_count() << endl; // 2
    p2 = nullptr; //自动析构
    cout << p3.use_count() << endl; // 1
    p2 = p3;
    cout << p2.use_count() << endl; // 2
    return 0;
}

operator=函数的实现比较垃圾,所以更改为如下:

#include <iostream>
#include <memory>
using namespace std;

namespace haizei {
class A {
public :
    A() {
        cout << "default constructor" << endl;
    }
    int x, y;
    ~A() {
        cout << "destructor" << endl;
    }
};
class shared_ptr {
public :
    shared_ptr();
    shared_ptr(A *);
    shared_ptr(const shared_ptr &);
    int use_count();
    A *operator->();
    A &operator*();
    //赋值运算符之所以要返回当前对象的引用,是为了支持连等的操作
    shared_ptr &operator=(const shared_ptr &);
    ~shared_ptr();
private :
    void decrease_by_one();
    void increase_by_one();
    int *cnt; //引用计数
    A *obj;
};

shared_ptr::shared_ptr() : obj(nullptr), cnt(nullptr) {}

shared_ptr::shared_ptr(A *obj) : obj(obj), cnt(new int(1)) {}

shared_ptr::shared_ptr(const shared_ptr &p) : obj(p.obj), cnt(p.cnt) { increase_by_one(); }

int shared_ptr::use_count() { return cnt ? *cnt : 0; }

A *shared_ptr::operator->() { return obj; }

A &shared_ptr::operator*() { return *obj; }

void shared_ptr::decrease_by_one() {
    if (this->cnt != nullptr) {
        *(this->cnt) -= 1;
        if (*(this->cnt) == 0) {
            delete this->obj;
            delete this->cnt;
        }
    }
    return ;
}

void shared_ptr::increase_by_one() {
    if (cnt != nullptr) {
        *cnt += 1; //cnt[0] += 1;
    }
    return ;
}

shared_ptr::~shared_ptr() {
    this->decrease_by_one();
    this->obj = nullptr;
    this->cnt = nullptr;
}

shared_ptr &shared_ptr::operator=(const shared_ptr &p) {
    //判断是否指向同一个对象
    if (this->obj != p.obj) {
        decrease_by_one(); //引用计数-1
        //拷贝对象
        obj = p.obj;
        cnt = p.cnt;
        increase_by_one(); //给新的引用计数+1
    }
    return *this;
}

} // end of haizei


int main() {
    haizei::A *p1 = new haizei::A();
    p1 = nullptr;

    //p2就是智能指针对象
    haizei::shared_ptr p2(new haizei::A());
    cout << p2.use_count() << endl; // 1
    haizei::shared_ptr p3 = p2;
    p2->x = 123; p2->y = 456;
    (*p2).x = 456;
    cout << p2.use_count() << endl; // 2
    p2 = nullptr; //自动析构
    cout << p3.use_count() << endl; // 1
    p2 = p3;
    cout << p2.use_count() << endl; // 2
    return 0;
}

运行结果:

default constructor
default constructor
1
2
1
2
destructor

至此,完成了简单的智能指针的实现。

4.10 调用对象

对数组进行排序:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

ostream &operator<<(ostream &out, const vector<int> &a) {
    for (auto x : a) {
        out << x << " ";
    }
    return out;
}

int main() {
    vector<int> arr;
    int n;
    cin >> n;
    while (n--) { int a; cin >> a, arr.push_back(a); }
    sort(arr.begin(), arr.end());
    cout << arr << endl;
    return 0;
}

sort函数默认是从小到大排序。如果想从大到小排序,一般是添加自定义一个比较函数:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

ostream &operator<<(ostream &out, const vector<int> &a) {
    for (auto x : a) {
        out << x << " ";
    }
    return out;
}

bool cmp1(int a, int b) {
    return a > b; //当a > b的时候,a排在b前面,也就是从大到小排序
}

int main() {
    vector<int> arr;
    int n;
    cin >> n;
    while (n--) { int a; cin >> a, arr.push_back(a); }
    sort(arr.begin(), arr.end(), cmp1);
    cout << arr << endl;
    return 0;
}

在学习了 仿函数 后,也可以使用 仿函数 来实现自定义比较规则:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

ostream &operator<<(ostream &out, const vector<int> &a) {
    for (auto x : a) {
        out << x << " ";
    }
    return out;
}

bool cmp1(int a, int b) {
    return a > b; //当a > b的时候,a排在b前面,也就是从大到小排序
}

class CMP {
public :
    bool operator()(int a, int b) {
        return a > b;
    }
};

int main() {
    vector<int> arr;
    int n;
    cin >> n;
    while (n--) { int a; cin >> a, arr.push_back(a); }
    //sort(arr.begin(), arr.end(), cmp1);
    sort(arr.begin(), arr.end(), CMP());//CMP()构造函数构造了一个匿名对象,第三个位置放置的应该是函数名,而仿函数的函数名就是对象名
    cout << arr << endl;
    return 0;
}

仿函数的功能是由重载的()运算符来决定的。

上面还可以改写为如下:

CMP cmp2;
sort(arr.begin(), arr.end(), cmp2);

仿函数比普通函数的功能更强大:根据z值的不同,使用不同的比较规则

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

ostream &operator<<(ostream &out, const vector<int> &a) {
    for (auto x : a) {
        out << x << " ";
    }
    return out;
}

bool cmp1(int a, int b) {
    return a > b; //当a > b的时候,a排在b前面,也就是从大到小排序
}

class CMP {
public :
    CMP(int z = 0) : z(z) {} //z = 0 less, z = 1 greater
    bool operator()(int a, int b) {
        return (a < b) ^ !!(z);
    }
    int z;
};

int main() {
    vector<int> arr;
    int n;
    cin >> n;
    while (n--) { int a; cin >> a, arr.push_back(a); }
    sort(arr.begin(), arr.end(), CMP());//CMP()就是一个匿名对象,第三个位置放置的应该是函数名,而仿函数的函数名就是对象名
    cout << arr << endl;
    return 0;
}

sort(arr.begin(), arr.end(), CMP()); 的是默认的情况,是从小到大排序;而sort(arr.begin(), arr.end(), CMP(1));就是从大到小排。

4.11 实现自己的 sort 函数

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

ostream &operator<<(ostream &out, const vector<int> &a) {
    for (auto x : a) {
        out << x << " ";
    }
    return out;
}

bool cmp1(int a, int b) {
    return a > b; //当a > b的时候,a排在b前面,也就是从大到小排序
}

namespace haizei {

class CMP {
public :
    CMP(int z = 0) : z(z) {} //z = 0 less, z = 1 greater
    bool operator()(int a, int b) {
        return (a < b) ^ !!(z);
    }
    int z;
};

//cmp是一个函数指针对象,本质是对象,表现得像个函数指针,返回值是bool,传入参数是两个int
void sort(int *arr, int l, int r, function<bool(int, int)> cmp = CMP()) {
    //就是快速排序
    if (l >= r) return ;
    int x = l, y = r, z = arr[(l + r) >> 1];
    do {
        while (cmp(arr[x], z)) ++x;
        while (cmp(z, arr[y])) --y;
        if (x <= y) {
            swap(arr[x], arr[y]);
            ++x, --y;
        }
    } while (x <= y);
    sort(arr, l, y, cmp);
    sort(arr, x, r, cmp);
    return ;
}

}; //end of haizei

int main() {
    vector<int> arr;
    int n;
    cin >> n;
    while (n--) { int a; cin >> a, arr.push_back(a); }
    //sort(arr.begin(), arr.end(), cmp1);
    sort(arr.begin(), arr.end(), haizei::CMP());//CMP()就是一个匿名对象,第三个位置放置的应该是函数名,而仿函数的函数名就是对象名
    cout << arr << endl;


    // ====使用自己写的sort函数
    int arr2[5] = {6, 8, 4, 5, 1};

    haizei::sort(arr2, 0, 4); //默认情况从小到大排
    for (int i = 0; i < 5; i++) {
        cout << arr2[i] << " ";
    }
    cout << endl;

    //从大到小排: 使用自定义函数
    haizei::sort(arr2, 0, 4, cmp1);
    for (int i = 0; i < 5; i++) {
        cout << arr2[i] << " ";
    }
    cout << endl;

    haizei::sort(arr2, 0, 4); //默认情况从小到大排
    for (int i = 0; i < 5; i++) {
        cout << arr2[i] << " ";
    }
    cout << endl;

    //从大到小排: 使用仿函数
    haizei::sort(arr2, 0, 4, haizei::CMP(1));
    for (int i = 0; i < 5; i++) {
        cout << arr2[i] << " ";
    }
    cout << endl;

    return 0;
}

运行结果:

5  #输入
1 4 2 0 9 #输入
0 1 2 4 9 #输出
1 4 5 6 8 #输出
8 6 5 4 1 #输出
1 4 5 6 8 #输出
8 6 5 4 1 #输出

系统 sort 函数之所以能传入可调用对象,是因为使用了function这个模板类。

上一篇:go语言的指针


下一篇:【C语言】PAT乙级1004 成绩排名 :读入 n(>0)名学生的姓名、学号、成绩,分别输出成绩最高和成绩最低学生的姓名和学号。