本节知识点:1.c++标准库: a.c++标准库并不是c++语言的一部分,c++标准库是由c++语言编写而成的类库和函数的集合。c++标准库中定义的类和对象都位于std命名空间中,c++标准库的头文件都不带.h后缀,并且c++标准库涵盖了c库的功能,如c库中<name.h>对应c++库中的<cname>
b.c++标准库预定义了多数常用的数据结构,如:<bitset> <deque> <list> <map> <queue> <set> <stack> <vector>
c.c++标准库中的cout和cin的使用方式(代码如下):
[cpp] view plaincopy
- #include <cstdio>
- #include <iostream>
- using
namespace std;
- int main()
- {
- int a;
- int b;
- printf("put a :\n");
- cin >> a;
- printf("put b :\n");
- cin >> b;
- cout << "sum is : " << a+b << endl;
- return 0;
- }
2.全局函数的操作符重载:
a.c++中可以通过operator关键字利用函数扩展操作符,即操作符重载,operator的本质是通过函数重载实现操作符的重载,所以操作符重载遵循函数重载的规则。
b.c++中类的友元的定义:private声明使得类的成员不能被外界访问,但是通过friend关键字可以以友元的形式开放权限。友元访问成员变量,依然是通过对象来访问,跟成员函数还是有很大区别的,普通成员函数可以直接访问成员变量,不需要对象。
代码示例如下:
[cpp] view plaincopy
- #include <iostream>
- using
namespace std; - class test
- {
- private:
- int a;
- int b;
- public:
- test (int a, int b)
- {
- this->a = a;
- this->b = b;
- }
- int geta()
- {
- return a;
- }
- int getb()
- {
- return b;
- }
- /*注意友元可以是任何形式的函数*/
- friend test operator+ (test& a1, test& a2); //友元声明
- };
- test operator+ (test& a1, test& a2) //全局操作符重载函数
- {
- test c(0,0);
- c.a = a1.a + a2.a;
- c.b = a1.b + a2.b;
- return c;
- }
- int main()
- {
- test n1(1,2);
- test n2(2,3);
- test n3(0,0);
- cout << "a is : " << n3.geta() <<endl;
- cout << "b is : " << n3.getb() <<endl;
- n3 = n1 + n2;
- cout << "a is : " << n3.geta() <<endl;
- cout << "b is : " << n3.getb() <<endl;
- return 0;
- }
注意:上代码中的 n1+n2 其实等价于 operator+(n1, n2)
3.类的成员函数的操作符重载: a.用成员函数重载操作符:比全局函数少一个参数,即左操作数,也是这个类的对象。同时不需要使用friend关键字:
代码如下:
[cpp] view plaincopy
- #include <iostream>
- #include <cstdio>
- using
namespace std; - class test
- {
- private:
- int a;
- int b;
- public:
- test(int a, int b)
- {
- this->a = a;
- this->b = b;
- }
- test operator+ (test& n2);
- friend test operator+ (test& n1, test& n2);
- friend ostream& operator<<(ostream& out , test& n);
- };
- ostream& operator<<(ostream& out , test& n)
- {
- out << "a is : " << n.a <<endl;
- out << "b is : " << n.b ;
- return out;
- }
- test test:perator+ (test& n2) //成员函数的操作符重载
- {
- test n3(0,0);
- n3.a = a + n2.a;
- n3.b = b + n2.b;
- return n3;
- }
- test operator+ (test& n1, test& n2) //全局函数的操作符重载
- {
- test n3(0,0);
- n3.a = n1.a + n2.a + 2;
- n3.b = n1.b + n2.b + 2;
- return n3;
- }
- int main()
- {
- test n1(2,2);
- test n2(3,3);
- test n3(0,0);
- //n3 = n1 + n2; //此处的n3 = n1 + n2 用不了 因为有二义性不知道是调用成员函数还是全局函数
- n3 = n1.operator+(n2); //成员函数的操作符重载 等效于n3 = n1 + n2;
- n3 = operator+ (n1, n2); //全局函数的操作符重载 等效于n3 = n1 + n2;
- cout << n3 <<endl; //这个<<的重载 不是成员函数的操作符重载 等价于 operator<<(cout,n3);
- operator<<(cout, n3)<<endl;
- cout.operator<< (55); //这个是<<在ostream类中的重载函数 的调用
- return 0;
- }
注意:成员函数的操作符重载,op1 符号 op2 等价于 op1.operator 符号 (op2) 所以说op1必须是这个类的对象
全局函数的操作符重载,op1 符号 op2 等价于 operator符号(op1, op2) 所以说op1和op2可以是任何类型
4.成员函数和全局函数的操作符重载适用情况: a.如果左操作数不是一个类的对象,只能用全局函数的操作符重载
b.当无法修改左操作数的类时,使用全局函数进行重载,就像前面重载的<<符号一样,因为不能修改ostream这个类,所以就只能使用全局函数的操作符重载
c.其实大量的成员函数的操作符重载,都可以被全局函数的操作符重载代替,但是对于=赋值操作符、[ ]数组运算操作符、()函数调用操作符、->指针操作符只能通过成员函数进行重载。(这四个操作符是c++编译器中的特殊规定只能使用成员函数进行操作符重载,不要问为什么,违反了编译会出错)
d.c++编译器会为每一个类提供一个默认的赋值操作符,默认的赋值操作符只是做简单的值的复制。当类中存在指针成员变量(尤其是指向new出来的内存的指针)时,就需要重载赋值操作符了,否则在析构函数中delete的时候,就会对同一个地址delete两次!!!
代码如下:
[cpp] view plaincopy
- #include <iostream>
- using
namespace std;
- class test
- {
- private:
- int a;
- int b;
- public:
- test(int a, int b)
- {
- this->a = a;
- this->b = b;
- }
- /* test(const test& n)
- {
- cout<<"hhhhhhh"<<endl;
- }*/
- test& operator= (test& n2);
- friend ostream& operator<<(ostream& out , test& n);
- };
- ostream& operator<<(ostream& out , test& n)
- {
- out << "a is : " << n.a <<endl;
- out << "b is : " << n.b ;
- return out;
- }
- test& test:perator= (test& n2)
- {
- a = n2.a + 10;
- b = n2.b + 10;
- return *this;
- }
- /**********************************************************************
- 这里面有一个有意思的东西,就是编译器提供的类的拷贝构造函数中,
- 有一个类对类赋值的过程 test a = b 是调用拷贝构造函数
- 编译器同时对类也提供了一个=赋值运算符的重载成员函数,负责简单
- 的类之间的赋值,如test a; a = b;这个过程就调用了这个重载的函数
- 但是他俩都有一个性质,就是如果用户定义了这个函数,编译器提供的
- 函数就失效了
- **********************************************************************/
- int main()
- {
- test a(2,2);
- test b = a; //调用拷贝构造函数中的赋值过程
- cout << b;
- // test b = test(0,0);
- // b = a; //调用编译器提供的 =赋值运算符的重载函数
- test c = test(9,9);
- b = c;
- cout << b;
- return 0;
- }
注意:第一,c++编译器会为类提供一个拷贝构造函数,提供一个赋值操作符重载函数。两个默认函数的功能相同,都是对类的成员变量进行简单的复制。
第二,但是两个函数之间是相互独立的,有各自的应用场景,如在test b = a; 类定义初始化的时候,此时调用的是类的拷贝构造函数。还有就是在函数参数为类的时候void fun(test a),在函数调用进行参数传递的时候,调用拷贝构造函数,实现实虚参之间的传递。如在b = a 两个类直接赋值的时候,调用的是默认赋值操作符重载函数。
第三,就是这两个默认提供的函数,一旦用户自己定义了,原来c++编译器提供的默认函数就会失效。
5.++操作符的重载: a.c++中通过一个占位参数来区分前置运算和后置运算,且++运算符的重载即可以是全局函数也可以是成员函数,代码如下:
[cpp] view plaincopy
- #include <iostream>
- using
namespace std; - class test
- {
- private:
- int a;
- int b;
- public:
- test(int a, int b)
- {
- this->a = a;
- this->b = b;
- }
- friend ostream& operator<<(ostream& out , test& n);
- friend test operator++ (test& a, int);
- friend test& operator++ (test& a);
- };
- ostream& operator<<(ostream& out , test& n)
- {
- out << "a is : " << n.a <<endl;
- out << "b is : " << n.b ;
- return out;
- }
- test operator++ (test& a, int) //a++ 后置运算
- {
- test ret = a;
- a.a++;
- a.b++;
- return ret;
- }
- test& operator++ (test& a) //++a 前置运算
- {
- ++a.a;
- ++a.b;
- return a;
- }
- int main()
- {
- test a(0,0);
- test b(9,9);
- test c(8,8);
- b = a++;
- cout << b << endl;
- cout << a << endl;
- cout << "~~~~~" << endl;
- c = ++a;
- cout << c << endl;
- cout << a << endl;
- return 0;
- }
注意: operator++ (test& a, int) 为a++ 后置运算,operator++(test& a) 为++a 前置运算
6.&&和||操作符的重载: a.特别注意不要对&&和||操作符进行重载,因为正常的&&和||内置实现了短路规则,但是操作符重载是靠函数重载来完成的,操作数作为函数参数传递,c++中的函数参数都会被求值,无法实现短路规则。
代码如下:
[cpp] view plaincopy
- #include <cstdlib>
- #include <iostream>
- using
namespace std;
- class Test
- {
- int i;
- public:
- Test(int i)
- {
- this->i = i;
- }
- Test operator+ (const Test& obj)
- {
- Test ret(0);
- cout<<"Test operator+ (const Test& obj)"<<endl;
- ret.i = i + obj.i;
- return ret;
- }
- bool operator&& (const Test& obj)
- {
- cout<<"bool operator&& (const Test& obj)"<<endl;
- return i && obj.i;
- }
- };
- int main(int argc, char *argv[])
- {
- int a1 = 0;
- int a2 = 1;
- if( a1 && (a1 + a2) )
- {
- cout<<"Hello"<<endl;
- }
- Test t1 = 0;
- Test t2 = 1;
- if( t1 && (t1 + t2) ) // 正常来说如果 t1为0 t1+t2是不应该被执行的
- {
- cout<<"World"<<endl;
- }
- return 0;
- }
注意:正常来说 上面的 t1+t2 是应该被短路的,不应该被执行的,但是由于t1+t2实质上是函数的参数,所以被执行了,违背了短路规则!!!
7.本节总结(几个常出面试题):
a. =赋值操作符 、[]数组操作符 、()函数调用操作符 、->指针操作符,这个四个操作符只能通过成员函数进行重载
b.++操作符通过一个int参数进行前置与后置的重载
c. c++中不要重载&&和||操作符 |