编译器是没有办法通过返回值来确认调用的是哪个函数的。
代码:
#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; }
冲突形式:参数有默认值
针对这种情况,可以将两个函数进行合并:
#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; }
无法通过返回值来做函数重载形式的区分:
若 类外的一个函数 想要访问类内部成员,需要将该函数声明成类的一个友元函数。
形式如下:
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; }
友元函数本质上是一个类外部的函数,声明为友元函数后虽然还是类外的函数,但是可以访问类内部的私有属性。
sizeof
也是运算符,也无法被重载,但是通常不被认为是运算符,而是函数。
注意:new
和delete
是运算符,malloc
是函数。
#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行是分别对
x
和y
进行赋值,第1行是将x
和y
都赋值为0,所以1行可以委托2行进行构造:Point::Point() : Point(0, 0) {} Point::Point(int x, int y) : x(x), y(y) {}
#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; }
类外重载和类内重载同时存在不会冲突,因为类内重载的优先级更高,同时存在的时候会调用类内重载。
=
)、下标([]
)、调用(()
)、成员访问(->
) 运算符必须重载为成员函数#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
上。
运算符的返回值是任意的,并没有规定一定要返回引用。
[]
重载出来的对象叫做==数组对象==;
[]
只支持==类内重载==
#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
对象的外在表现像一个数组,但是它的本质还是一个对象。所以将重载了 []
运算符的类产生的对象,叫做数组对象,就是外在表现是一个数组,但是本质上还是一个对象。
()
重载出来的对象叫做函数对象,也叫==仿函数==;
#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
对象表现得像个函数,但是本质是个对象,所以叫做函数对象,也叫做可调用对象,也称仿函数。
->
(间接引用)重载出来的对象叫做 指针对象。
#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
表现得像个指针,但是本质上是个对象,所以叫做对象指针。
智能指针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
至此,完成了简单的智能指针的实现。
对数组进行排序:
#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));
就是从大到小排。
#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
这个模板类。