this指针
this指针代表的就是当前对象本身,是作为成员函数的第一个隐含的参数,编译器在编译时会自动加上,不需要程序员手动提供
this指针不可以被修改
this指针作为隐含参数
对象的复制
赋值运算符函数形式:类名& operator=(const 类名&);
Point & operator=(const Point & rhs)
{
_ix=rhs._ix;
_iy=rhs._iy;
cout<<"Point & operator=(const Point &)"<<endl;
}
1.返回值可以不返回引用吗?
可以,但是返回对象时相当于做了一次复制操作,增加了系统开销
1 #include <iostream>
2 using std::cout;
3 using std::endl;
4 using std::cin;
5
6 class Point
7 {
8 public:
9 Point()=default;
10
11 Point(int ix,int iy)
12 :_ix(ix)
13 ,_iy(iy)
14 {
15 /* cout<<"Point()"<<endl; */
16 }
17
18 Point(const Point & rhs)
19 :_ix(rhs._ix)
20 ,_iy(rhs._iy)
21 {
22 cout<<"拷贝构造函数调用"<<endl;
23 }
24
25 Point & operator=(const Point & rhs)
26 {
27 /* this=1000;//error */
28 _ix=rhs._ix;
29 _iy=rhs._iy;
30 cout<<"Point & operator=(const Point &)"<<endl;
31 return * this;
32 }
33
34 void printInfo(){
35 cout<<"("<<_ix
36 <<","<<_iy
37 <<")"<<endl;
38 }
39
40
41 ~Point()
42 {
43 /* cout<<"析构函数调用"<<endl; */
44 }
45
46 private:
47 int _ix;
48 int _iy;
49 };
50
51 void test0(){
52 Point pt1(1,1);
53 Point pt2(2,2);
54 pt2=pt1;
55 pt1.printInfo();//==pt1.printInfo(&pt1)
56 // ==Point::prinInfo(&pt1)
57 }
58
59 int main()
60 {
61 test0();
62 return 0;
63 }
增加引用
不加引用
2.返回值可以是void吗?
不可以
编译结果
赋值函数报错的情况
1 #include <iostream>
2 #include <string.h>
3 using std::cout;
4 using std::endl;
5
6 class Computer
7 {
8 public:
9 Computer()=default;
10 Computer(const char * brand,float price)
11 :_brand(new char[strlen(brand)+1])
12 ,_price(price)
13 {
14 cout<<"构造函数调用"<<endl;
15 }
16 //拷贝构造函数 深拷贝
17 Computer(const Computer &rhs)
18 :_brand(new char[strlen(rhs._brand)+1]())
19 ,_price(rhs._price)
20 {
21 strcpy(_brand,rhs._brand);
22 cout<<"拷贝构造函数调用,深拷贝"<<endl;
23 }
24 ~Computer(){
25 if(_brand){
26 delete [] _brand;
27 _brand=nullptr;
28
29 }
30 cout<<"~Computer()"<<endl;
31 }
32
33 Computer & operator=(const Computer & rhs)
34 {
35 _brand=rhs._brand;
36 _price=rhs._price;
37 cout<<"Computer & operator=(const Computer& rhs)"<<endl;
38 return *this;
39 }
40 private:
41 char *_brand;
42 float _price;
43 };
44 void test0()
45 {
46 Computer c1("macbook",9999);
47 Computer c2("华为matebook",8888);
48 c2=c1;
49 }
50
51 int main()
52 {
53 test0();
54 return 0;
55 }
运行结果
原因:与拷贝构造哪里同理,两个指针指向了同一块堆空间,调用析构函数的时候,对同一个堆空间释放了两次
解决策略
1回收左操作数申请的空间,2进行深拷贝
运行结果
三合成原则
当类中需要显式提供析构函数、拷贝构造函数、赋值运算符函数中的其中一个时,另外两个也需要提供
特殊的数据成员的初始化
1.const数据成员 2.引用数据成员 3.对象数据成员 4.静态数据成员,前三者的初始化都必须要放入初始化列表中进行
const数据成员
放入初始化列表
引用数据成员
对象成员
1 #include <iostream>
2 using std::cout;
3 using std::endl;
4 using std::cin;
5
6 class Point
7 {
8 public:
✹ 9 Point()=default;
10
11 Point(int ix,int iy)
12 :_ix(ix)
13 ,_iy(iy)
✹ 14 ,_ref(iy)
15 {
16 /* _ref=iy; */
17 /* cout<<"Point()"<<endl; */
18 }
19
20 Point & operator=(const Point & rhs)
21 {
22 /* this=1000;//error */
23 _ix=rhs._ix;
24 _iy=rhs._iy;
25 cout<<"Point & operator=(const Point &)"<<endl;
✹ 26 }
27
28 void printInfo(){
29 cout<<"("<<_ix
30 <<","<<_iy
31 <<")"<<endl;
32 }
33
34 ~Point()
35 {
36 /* cout<<"析构函数调用"<<endl; */
37 }
39 private:
40 int _ix;
41 int _iy;
42 int &_ref;//引用数据成员
43 };
44
45 class Line
46 {
47 public:
48 Line(int x1,int y1,int x2,int y2)
49 :_p1(x1,y1)
50 ,_p2(x2,y2)
51 {
52 cout<<"Line()"<<endl;
53 }
54 void printLine(){
55 _p1.printInfo();
56 cout<<endl;
57 _p2.printInfo();
58 }
59
60 private:
61 Point _p1;
62 Point _p2;
63 };
64
65 void test1()
66 {
67 Line l1(1,2,3,4);
68 l1.printLine();
69 }
70
71 Point test2()
72 {
73 Point pt1(1,1);
74 return pt1;
75 }
76
77 int main()
78 {
79 test1();
80 return 0;
81 }
运行结果
静态数据成员
static 全局静态区,在类中定义的static数据成员,也是放在全局静态区的=》不会占据类或者对象的存储空间,静态数据成员会被整个类创建的对象所共享
1 #include <iostream>
2 #include <string.h>
3 using std::cout;
4 using std::endl;
5
6 class Computer
7 {
8 public:
9 Computer()=default;
10 Computer(const char * brand,float price)
11 :_brand(new char[strlen(brand)+1])
12 ,_price(price)
13 {
14 total_price+=_price;
15 cout<<"构造函数调用"<<endl;
16 }
17 //拷贝构造函数 深拷贝
18 Computer(const Computer &rhs)
19 :_brand(new char[strlen(rhs._brand)+1]())
20 ,_price(rhs._price)
21 {
22 strcpy(_brand,rhs._brand);
23 cout<<"拷贝构造函数调用,深拷贝"<<endl;
24 }
25
26 ~Computer(){
27 if(_brand){
28 delete [] _brand;
29 _brand=nullptr;
30
31 }
32 cout<<"~Computer()"<<endl;
33 }
34
35 Computer & operator=(const Computer & rhs)
36 {
37 if(this!=&rhs){
38 delete [] this->_brand;
39 _brand=new char[strlen(rhs._brand)+1]();
40 strcpy(_brand,rhs._brand);
41 this->_price=rhs._price;
42 }
43
44 cout<<"Computer & operator=(const Computer& rhs)"<<endl;
45 return *this;
46 }
47
48 void printinfo()
49 {
50 cout<<"总价格为:"<<total_price
51 <<"电脑品牌:"<<this->_brand
52 <<"价格为:"<<this->_price<<endl;
53 }
54 private:
55 char *_brand;
56 float _price;
57 static float total_price;
58 };
59
60 float Computer::total_price=0;
61
62 void test0()
63 {
64 Computer c1("macbook",9999);
65 Computer c2("华为matebook",8888);
66 c2=c1;
67 c2.printinfo();
68 }
69
70 int main()
71 {
72 test0();
73 return 0;
74 }
运行结果,说明静态变量存在全局静态区
静态成员函数
在一个普通的成员函数前面加上static关键字,该函数就成为static成员函数。
静态成员函数没有隐含的this指针,不能访问非静态的数据成员和成员函数,只能访问静态的数据成员和成员函数,可以直接通过类名调用, 不需要对象的存在。
如图,静态成员函数没有隐含的this指针
不能访问非静态得数据成员和成员函数
可以通过类名调用,不需要对象的存在
运行结果
const成员函数
const关键字放在成员函数的形参列表之后,就称为const成员函数
注意:只要成员函数不会对数据成员进行修改,都应该将其设计为const成员函数,const成员函数只能读取数据成员,不能修改数据成员
const关键字的作用是:修改了this指针的形式,让其变成了双重限定的this指针
空指针的使用情况
1 #include <iostream>
2 using std::cout;
3 using std::endl;
4
5 class NullPointer
6 {
7 public:
8 void test1(){
9 cout<<"test1()"<<endl;
10 }
11 void test2(int x){
12 cout<<"test2() x"<<x<<endl;
13 }
14 void test3(){
15 cout<<"test3()"<<this->_ix<<endl;
16 }
17 static void test4(){
18 cout<<"test4()"<<endl;
19 }
20
21 private:
22 int _ix;
23
24 };
25
26 void test0()
27 {
28 NullPointer* np=nullptr;
29 np->test1();
30 np->test2(1);
31 np->test4();
32 np->test3();
33 }
34
35 int main()
36 {
37 test0();
38 return 0;
39 }
运行结果
test3发生段错误的原因,只有test3函数内部需要访问数据成员_ix,而传递过去的是一个空指针,没有对象可以使用,所以报错。
单例模式
单例模式是23种设计模式中最简单最常见的一种,要求通过一个类只能创建一个对象。
单例模式的应用场景
1.单例模式可以用来替换全局变量
2.配置文件中的信息可以存储在单例对象中
3.网页库,倒排索引库都可以使用单例模式
实现单例模式的具体步骤
1.在类中定义一个静态的指向本类型的指针
2.将构造函数私有化
3.在public区域定义一个静态成员函数
单例模式实例
1 #include <iostream>
2 using std::cout;
3 using std::endl;
4
5 class Singleton
6 {
7 public:
8 static Singleton * getInstance()
9 {
10 if(_p==nullptr)
11 {
12 _p=new Singleton;
13 }
14 return _p;
15 }
16 void init(int ix,int iy)
17 {
18 _ix=ix;
19 _iy=iy;
20 }
21 void destroySingleton()
22 {
23 if(_p!=nullptr)
24 {
25 delete _p;
26 _p=nullptr;
27 }
28 }
29
30 private:
31 Singleton(int ix=0,int iy=0)
32 :_ix(ix)
33 ,_iy(iy)
34 {
35 cout<<"Singleton()"<<endl;
36 }
37 ~Singleton()
38 {
39 cout<<"~Singleton()"<<endl;
40 }
41
42 private:
43 int _ix;
44 int _iy;
45 static Singleton *_p;
46 };
47
48 Singleton* Singleton::_p=nullptr;
49
50 void test0()
51 {
52 Singleton *s1=Singleton::getInstance();
53 Singleton *s2=Singleton::getInstance();
54 cout<<"&s1:"<<s1<<endl;
55 cout<<"&s:2"<<s2<<endl;
56 // Singleton s1;//error 使用单例模式只能创建一个对象
57 s2->destroySingleton();
58 }
59
60
61 int main()
62 {
63 test0();
64 return 0;
65 }
运行结果也表明只能创建一个对象