C++ learn

记录一些学c++的笔记吧,主要是跟着b站黑马程序员学的,众所周知,B站是学习网站。目前进度,核心编程学了,提高编程未学。

C++基础入门

就基础方面的话,和c大致差不多,不同点就写下面吧。

输入,输出

c++多了一种输入输出的方式,cin,cout。

1
2
3
4
5
6
7
8
9
10
11
12

#include<iostream>
using namespace std;

int main()
{
int a=10;
char ch;
cin >> ch;
cout << ch <<"="<< a << endl;
}

string变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

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

int main()
{
char ch[10]="hellow";
//ch[10] = "abc";C语言的这种字符串是不能直接改变内容的

string str="world";
str = "abc";//可以看到string类型是可以直接赋值的
cout << str << endl;

}

实战-通讯录管理资料

跟着资料写一写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247

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

struct person
{
string name;
int sex;
int age;
string phone;
string address;
};

int num=0;
int isexit(struct person *arr, string name)
{
int i;
for (i = 0; i < num; i++)
{
if (arr[i].name == name)
{
return i;
}
}
return -1;
}
void welcome()
{
cout << "***************************" << endl;
cout << "***** 1、添加联系人 *****" << endl;
cout << "***** 2、显示联系人 *****" << endl;
cout << "***** 3、删除联系人 *****" << endl;
cout << "***** 4、查找联系人 *****" << endl;
cout << "***** 5、修改联系人 *****" << endl;
cout << "***** 6、清空联系人 *****" << endl;
cout << "***** 0、退出通讯录 *****" << endl;
cout << "***************************" << endl;
}
void addcontacts(struct person *arr)
{
if (num >= 1000)
{
cout << "通讯录已满" << endl;
}
else
{
string name;
cout << "请输入姓名:" << endl;
cin >> name;
arr[num].name = name;
int sex;
cout << "请输入性别:" << endl;
cout << "1 -- 男" << endl;
cout << "2 -- 女" << endl;
while (true)
{
cin >> sex;
if (sex == 1 || sex == 2)
{
arr[num].sex = sex;
break;
}
cout << "输入有误,请重新输入";
}
cout << "请输入年龄" << endl;
int age;
cin >> age;
arr[num].age = age;
cout << "请输入电话号码" << endl;
string phone;
cin >> phone;
arr[num].phone = phone;
cout << "请输入家庭住址" << endl;
string address;
cin >> address;
arr[num].address = address;
num++;
cout << "添加成功" << endl;
system("pause");
system("cls");
}
}

void showcontacts(struct person *arr)
{
int i;
if (num == 0)
{
cout << "当前通讯录里面没有联系人" << endl;
}
else
{
for (i = 0; i < num; i++)
{
cout << "姓名:" << arr[i].name << "\t";
cout << "性别:" << arr[i].sex << "\t";
cout << "年龄:" << arr[i].age << "\t";
cout << "电话号码:" << arr[i].phone << "\t";
cout << "家庭地址:" << arr[i].address << endl;
}
}
system("pause");
system("cls");

}
void deletecontacts(struct person* arr)
{
string name;
int i;
int target;
cout << "请输入要删除的联系人" << endl;
cin >> name;
target = isexit(arr, name);
if (target == -1)
{
cout << "没有这个人" << endl;
}
else
{
for (i = target; i < num; i++)
{
arr[i] = arr[i + 1];
}
num--;
cout << "删除成功" << endl;
}
system("pause");
system("cls");
}

void findcontacts(struct person* arr)
{
string name;
int target = 0;
cout << "请输入要查找的联系人" << endl;
cin >> name;
target = isexit(arr, name);
if (target == -1)
{
cout << "没有这个人" << endl;
}
else
{

cout << "姓名:" << arr[target].name << "\t";
cout << "性别:" << arr[target].sex << "\t";
cout << "年龄:" << arr[target].age << "\t";
cout << "电话号码:" << arr[target].phone << "\t";
cout << "家庭地址:" << arr[target].address << endl;
}
system("pause");
system("cls");
}
void modifycontact(struct person* arr)
{
string name;
int target;
cout << "请输入要修改的联系人" << endl;
cin >> name;
target = isexit(arr, name);

if (target == -1)
{
cout << "没有这个人" << endl;
}
else
{
cout << "请输入姓名:" << endl;
cin >> name;
arr[target].name = name;
int sex;
cout << "请输入性别:" << endl;
cout << "1 -- 男" << endl;
cout << "2 -- 女" << endl;
while (true)
{
cin >> sex;
if (sex == 1 || sex == 2)
{
arr[target].sex = sex;
break;
}
cout << "输入有误,请重新输入";
}
cout << "请输入年龄" << endl;
int age;
cin >> age;
arr[target].age = age;
cout << "请输入电话号码" << endl;
string phone;
cin >> phone;
arr[target].phone = phone;
cout << "请输入家庭住址" << endl;
string address;
cin >> address;
arr[target].address = address;
cout << "修改成功" << endl;
}

system("pause");
system("cls");
}
void deleteallcontacts(struct person* arr)
{
num = 0;
cout << "所有联系人删除成功" << endl;
system("pause");
system("cls");
}
int main()
{
int choice;
person arr[10];
while (1)
{
welcome();
cin >> choice;
switch (choice)
{
case 1:
addcontacts(arr);
break;
case 2:
showcontacts(arr);
break;
case 3:
deletecontacts(arr);
break;
case 4:
findcontacts(arr);
break;
case 5:
modifycontact(arr);
break;
case 6:
deleteallcontacts(arr);
break;
case 0:
cout << "欢迎下次使用" << endl;
system("pause");
return 0;
break;
}
}

}

C++核心编程

堆空间的申请与释放

c采用不同于malloc,free的方式来向堆区申请与释放空间,而c++还可以用new和delete来向堆区申请与释放空间

#include<iostream>
using namespace std;

int main()
{
    int* p = new int(10);
    int  i;
    cout << *p << endl;
    delete p;
    int* q = new int[10];
    for (i = 0; i < 10; i++)
    {
        q[i] = i;
    }
    for (i = 0; i < 10; i++)
    {
        cout << q[i] << endl;
    }
    delete[] q;
}

引用&

1.c++中的一个知识点,先通过一个例子来认识引用

1
2
3
4
5
6
7
8
9
10
11
12
13
14

#include<iostream>
using namespace std;

void main() {

int a=0;
int& b = a;//表面上就是相当于给a取个别名叫b

b = 2;
cout << &b << "\t" << &a << endl;//会发现两个值是一样的
cout << b << "\t" << a << endl;

}

我们继续通过汇编来看看究竟引用干了什么。

1
2
3
4
5
6
7
8
9
10

int a=0;
001D2602 mov dword ptr [a],0
int& b = a;//可以看到,这个语句就是将a变量的地址给了b
001D2609 lea eax,[a]
001D260C mov dword ptr [b],eax

b = 2;//对b进行赋值实际上也是对a在操作
001D260F mov eax,dword ptr [b]
001D2612 mov dword ptr [eax],2

引用&,表面上理解为一种改名操作吧,也是一种特殊的变量类型。

2.然后就是引用的函数应用了,我们都知道,想要用函数来对两个数的值进行真正的交换要用到指针,可是,在c++里面也可以用引用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

#include<iostream>
using namespace std;

void swap(int& m, int& n)
{
int tmp;
tmp = m;
m = n;
n = tmp;
}

void main() {

int a=10;
int b = 20;
swap(a, b);
cout << a << "\t" << b << endl;
}

可以看到,传入函数的类型居然和函数设置的不一样了,非常不寻常,还是觉得指针用起舒服,实际上感觉这种还是用到的指针,&m,&n,就是a
和b的地址。

3.返回静态变量引用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

#include<iostream>
using namespace std;

int& func()
{
static int a = 10;//定义了一个静态变量,这种变量储存在全局去,程序完成后释放。
cout << &a << endl;
return a;
}
int re()
{
return 10;
}

void main()
{
int& tmp = func();
cout << &tmp << endl;
cout << &func() << endl;
func() = 20;//可以看到函数返回值也可以赋值了。

}

里面打印出的地址全是一样的

4.引用的本质,实际上就是个静态指针,或者说是指针常量,也就是指向不能改变的指针。

1
2
3
4
5
6
7
8
9
10
11
12

#include<iostream>
using namespace std;

void main()
{
int a =10;

int& b = a;
int* const p = &a;//这两个意思是一样,只是语法上有差异。

}

意思就是,我们在写出int& b = a;时,就相当于定义了一个不可修改的指针(int * const p;),然后让p指向了a的地址。

5.常量引用,由于常量不可变,而且在全局区,无法直接引用,必须加const。

1
2
3
4
5
6
7
8
9

#include<iostream>
using namespace std;

void main()
{
int& a = 10;//可以看到这种引用是不行的,对一个常量,不能直接引用。
const int& b = 10;//可以理解为编译器生成了一个变量const int p=10,然后引用了这个p。
}

函数提高

1.函数默认参数,函数形参可以有默认参数(且从这个默认参数开始都要设置为默认参数),感觉没啥用样,直接在函数内弄一个变量不就可以了吗。

2.函数占位参数

1
2
3
4
5
6
7
8
9
10
11
12
13

#include<iostream>
using namespace std;

int func(int a, int)
{
return a;
}

void main()
{
func(10, 10);//调用该函数时一定要将这个占位参数给填充。
}

3.函数重载,就是在满足一定条件下

函数重载满足条件:

  • 同一个作用域下
  • 函数名称相同
  • 函数参数类型不同 或者 个数不同 或者 顺序不同

注意

  • 对于有默认参数的函数,别用函数重载
  • 对于引用时,特别是引用常量,注意有无const。

感觉没必要啊,改个函数名的事情。

类和对象

终于面向对象了。

封装

封装是C++面向对象三大特性之一

封装的意义:

  • 将属性和行为作为一个整体,表现生活中的事物
  • 将属性和行为加以权限控制

直接上两个例子,再来说需要注意的点。

案例1,设计立方体类(Cube),分别用全局函数和成员函数判断两个立方体是否相等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71

#include<iostream>
using namespace std;
class Cube {
public:
void setm_l(int l)
{
m_l = l;
}

void setm_h(int h)
{
m_h = h;
}

void setm_w(int w)
{
m_w = w;
}
int getm_l()
{
return m_l;
}

int getm_h()
{
return m_h;
}

int getm_w()
{
return m_w;
}

bool is_same1(Cube tmp)
{
if (tmp.m_h == m_h && tmp.m_l == m_l && tmp.m_w == m_w);
{
cout << "两个立方体一样" << endl;
}
return false;
}
private:
int m_l, m_h, m_w;
};


bool is_same2(Cube c1,Cube c2)
{
if (c1.getm_h() == c2.getm_h() && c1.getm_h() == c2.getm_l()&&c1.getm_w()==c2.getm_w());
{
cout << "两个立方体一样" << endl;
}
return false;
}

int main()
{
Cube c1;
c1.setm_h(10);
c1.setm_l(10);
c1.setm_w(10);
Cube c2;
c2.setm_h(10);
c2.setm_l(10);
c2.setm_w(10);

c1.is_same1(c2);
is_same2(c1, c2);
system("pause");
}

案例2,设计一个圆形类(Circle),和一个点类(Point),计算点和圆的关系。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86

#include<iostream>
using namespace std;

class Point {
public:
void setx(int x)
{
m_x = x;
}
void sety(int y)
{
m_y = y;
}
int getx()
{
return m_x;
}
int gety()
{
return m_y;
}
private:
int m_x, m_y;
};
class Circle {
public:
void setcenter(Point ct)
{
center = ct;
}
void setr(int r)
{
m_r = r;
}
Point getcenter()
{
return center;
}
int getr()
{
return m_r;
}

private:
Point center;
int m_r;
};




void check(Point p, Circle c)
{
int d;
int r;
d = (c.getcenter().getx() - p.getx()) * (c.getcenter().getx() - p.getx()) +
(c.getcenter().gety() - p.gety()) * (c.getcenter().gety() - p.gety());
r = c.getr() * c.getr();
if (d < r)
{
cout << "在圆内" << endl;
}
else if (d == r)
{
cout << "在圆上" << endl;
}
else
{
cout << "在圆外" << endl;
}
}
int main()
{
Point center, point;
Circle yuan;
center.setx(10);
center.sety(20);
point.setx(5);
point.sety(30);
yuan.setcenter(center);
yuan.setr(15);

check(point, yuan);
system("pause");
}

现在来说说封装吧,可以看到在class类中,有三种访问权限

  • 三种权限
  • 公共权限 public 类内可以访问 类外可以访问
  • 保护权限 protected 类内可以访问 类外不可以访问
  • 私有权限 private 类内可以访问 类外不可以访问

然后class与我们以前学习的struct很像,但是有一点不同,那就是访问权限,class里面属性的访问权限是默认是private的,而struct是public的。

对于class的private权限,有两个好处

  • 将所有成员属性设置为私有,可以自己控制读写权限,就像两个例子里面的一样。
  • 对于写权限,我们可以检测数据的有效性,比如说写入属性时,必须要满足什么条件,才可以写入。

对象的初始化和清理

1.其实讲的就是构造函数和析构函数,实际上就算我们不写构造和析构,编译器也默认会提供空实现(但是构造函数的拷贝函数不是空实现)。

  • 构造函数:主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无须手动调用。
  • 析构函数:主要作用在于对象销毁前系统自动调用,执行一些清理工作。

编译器默认的构造函数和析构函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

#include<iostream>
using namespace std;
class Person
{
public:
//构造函数
Person()
{
cout << "Person的构造函数调用" << endl;
}
Person(const Person &p)//注意这个拷贝,用的是引用,也就是本体,这样就不会在传入形参时又拷贝一份了
{
a = p.a;//拷贝操作
}
//析构函数
~Person()
{
cout << "Person的析构函数调用" << endl;
}
int a;
};

void test01()
{
Person p;
}

int main() {

test01();
system("pause");
return 0;
}

语法这些后面的例子会存在,我想先写一个老师没讲的析构函数特点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

#include<iostream>
using namespace std;
class person {
public:
~person()
{
if (h == 10)
{
cout << "p1" << endl;
}
else if (h == 11)
{
cout << "p2" << endl;
}
}
int h;
};
void test1()
{
person p1;
p1.h = 10;
person p2;
p2.h = 11;
}
int main()
{
test1();
}

这个的打印结果先是p2,后是p1,证明在这个例子中p2这个对象是先销毁的,我猜测可能和栈的结构有关吧,先入后出,后人先出,只是个人猜测。

2.构造函数的分类,老师讲的很详细,就直接腾过来了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

//1、构造函数分类
// 按照参数分类分为 有参和无参构造 无参又称为默认构造函数
// 按照类型分类分为 普通构造和拷贝构造

class Person {
public:
//无参(默认)构造函数
Person() {
cout << "无参构造函数!" << endl;
}
//有参构造函数
Person(int a) {
age = a;
cout << "有参构造函数!" << endl;
}
//拷贝构造函数
Person(const Person& p) {
age = p.age;
cout << "拷贝构造函数!" << endl;
}
//析构函数
~Person() {
cout << "析构函数!" << endl;
}
public:
int age;
};

//2、构造函数的调用
//调用无参构造函数
void test01() {
Person p; //调用无参构造函数
}

//调用有参的构造函数
void test02() {

//2.1 括号法,常用
Person p1(10);
//注意1:调用无参构造函数不能加括号,如果加了编译器认为这是一个函数声明
//Person p2();

//2.2 显式法
Person p2 = Person(10);
Person p3 = Person(p2);
//Person(10)单独写就是匿名对象 当前行结束之后,马上析构

//2.3 隐式转换法
Person p4 = 10; // Person p4 = Person(10);
Person p5 = p4; // Person p5 = Person(p4);

//注意2:不能利用 拷贝构造函数 初始化匿名对象 编译器认为是对象声明
//Person p5(p4);
}

int main() {

test01();
//test02();

system("pause");

return 0;
}

3.拷贝构造函数调用时机

  • 使用一个已经创建完毕的对象来初始化一个新对象
  • 值传递的方式给函数参数传值
  • 以值方式返回局部对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

#include<iostream>
using namespace std;
class Person
{
public:
//构造函数
Person()
{
cout << "Person的构造函数调用" << endl;
}
Person(const Person &p)
{
age = p.age;
}
int age;
};

void test01()
{
Person p;
Person p1(p);
}

void test02(Person p)
{

}

Person test03()
{
Person p;
return p;
}
int main() {
//使用一个已经创建完毕的对象来初始化一个新对象
test01();
//值传递的方式给函数参数传值
Person person;
test02(person);
//以值方式返回局部对象
Person q = test03();
}

4.深拷贝与浅拷贝,这个就比较有意思了

浅拷贝,就是编译器默认提供的拷贝,平时普通拷贝到没事,但是如果遇到在堆区申请的空间要拷贝是就会出问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

#include<iostream>
using namespace std;
class Person
{
public:
//构造函数
Person(int age,int hight)
{
m_age = age;
m_hight = new int(hight);
}
~Person()
{
if (m_hight != NULL)
{
delete m_hight;
}
}
int m_age;
int* m_hight;
};

void test01()
{
Person p(15,170);
Person p1(p);
}

int main() {
test01();
}

上面程序会崩,为什么,因为我在定义对象p时,向堆区申请了一块空间,然后将对象p拷贝给对象p1时,编译器默认的拷贝函数也将申请的堆空间地址给了p1的m_hight属性,这两个地址是一样的,这些都没有问题。

问题就出在析构函数,我在析构函数中写了释放堆空间的代码,申请了就要释放,没有问题,而且根据我上面讲的案例,p1这个对象会先被销毁,销毁后申请的堆空间也没了,然后p对象在被销毁时,delete又释放那个空间,就会出问题。

为了解决这种问题,就有了深拷贝。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

#include<iostream>
using namespace std;
class Person
{
public:
//构造函数
Person(int age,int hight)
{
m_age = age;
m_hight = new int(hight);
}
Person(const Person& tmp)
{
m_age = tmp.m_age;
m_hight = new int(*tmp.m_hight);
}
~Person()
{
if (m_hight != NULL)
{
delete m_hight;
}
}
int m_age;
int* m_hight;
};

void test01()
{
Person p(15,170);
Person p1(p);
}

int main() {
test01();
}

5.初始化列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

#include<iostream>
using namespace std;
class Point
{
public:
//传统初始化参数
//Point(int x, int y)
//{
// m_x = x;
// m_y = y;
//}

//初始化列表方式
Point(int x, int y) :m_x(x), m_y(y)
{
//里面还可以写些其他的能内容
}
int m_x;
int m_y;
};

int main() {
Point(1, 2);
}

7.类对象作为类成员

这种我们之前在写圆和点关系的案例中实际上就用到过了。

先上例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

#include<iostream>
using namespace std;
class Point
{
public:
//无参构造
Point()
{

}
//有参构造
Point(int x, int y)
{
m_x = x;
m_y = y;
}
int m_x;
int m_y;
};
class Cirle
{
public:
//可以通过初始化列表来告诉编译器调用Point的那一个构造函数
Cirle(int r, int x, int y) :m_r(r), m_point(x, y)
{
m_r = r;
}
int m_r;
Point m_point;
};

int main()
{
Cirle(1, 2, 3);
}

有一个可以讨论的问题,究竟是m_point这个对象先产生,还是Cirle对象先产生,答案是m_point对象先产生,Cirle对象后产生,而且析构销毁时,Cirle对象先被销毁,m_point对象后被销毁。

8.静态成员

静态成员就是在成员变量和成员函数前加上关键字static,称为静态成员

静态成员分为:

  • 静态成员变量
    • 所有对象共享同一份数据
    • 在编译阶段分配内存
    • 类内声明,类外初始化
  • 静态成员函数
    • 所有对象共享同一个函数
    • 静态成员函数只能访问静态成员变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

//静态对象
#include<iostream>
using namespace std;
class Point
{
public:
static int m_x;
private:
static int m_y;//类外无法访问
};
//初始化静态变量,在类外初始化
int Point::m_x = 10;
int Point::m_y = 10;
int main()
{
Point a;
Point b;
//用对象来访问静态变量
cout << a.m_x << "\t" << b.m_x << endl;
//用类名来访问静态变量
cout << Point::m_x << endl;
//修改某一个对象的静态成员,所有对象的静态成员都改变了。
a.m_x = 20;
cout << a.m_x << "\t" << b.m_x << endl;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

class Person
{

public:

//静态成员函数特点:
//1 程序共享一个函数
//2 静态成员函数只能访问静态成员变量

static void func()
{
cout << "func调用" << endl;
m_A = 100;
//m_B = 100; //错误,不可以访问非静态成员变量
}

static int m_A; //静态成员变量
int m_B; //
private:

//静态成员函数也是有访问权限的
static void func2()
{
cout << "func2调用" << endl;
}
};
int Person::m_A = 10;


void test01()
{
//静态成员变量两种访问方式

//1、通过对象
Person p1;
p1.func();

//2、通过类名
Person::func();


//Person::func2(); //私有权限访问不到
}

int main() {

test01();

system("pause");

return 0;
}

C++对象模型和this指针

1.在C++中,类内的成员变量和成员函数分开存储,只有非静态成员变量才属于类的对象上,而且对于一个空类,其占一个字节。

2.this指针

this指针指向被调用的成员函数所属的对象

this指针的用途:

  • 当形参和成员变量同名时,可用this指针来区分
  • 在类的非静态成员函数中返回对象本身,可使用return *this
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

#include<iostream>
using namespace std;
class Person
{
public:
Person(int m_num)
{
//可以看到传入形参名称和属性名称一样,这时候需要用this指针来区别。
this->m_num = m_num;
}

//返回为Person类型,相当于用了拷贝函数产生了一个新对象
Person add1(Person p)
{
this->m_num += p.m_num;
return *this;
}

//返回为Person&类型,就是原对象本身。
Person& add2(Person p)
{
this->m_num += p.m_num;
return *this;
}

int m_num;
};
void test01()
{
Person p1(10);
//链式结构
p1.add1(p1).add1(p1).add1(p1).m_num;
cout << p1.m_num << endl;
}
void test02()
{
Person p2(10);

p2.add2(p2).add2(p2).add2(p2).m_num;
cout << p2.m_num << endl;
}
int main()
{
test01();
test02();
system("pause");
}

3.空指针访问成员函数

Person *p=NULL;,这种空指针可以访问类中的成员函数,但是如果用到了this指针,就不可以了,因为这时候相当于this指针是空指针,没有指向任何一个对象。

4.const修饰成员函数,直接复制过来了

常函数:

  • 成员函数后加const后我们称为这个函数为常函数
  • 常函数内不可以修改成员属性
  • 成员属性声明时加关键字mutable后,在常函数中依然可以修改

常对象:

  • 声明对象前加const称该对象为常对象
  • 常对象只能调用常函数

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

class Person {
public:
Person() {
m_A = 0;
m_B = 0;
}

//this指针的本质是一个指针常量,指针的指向不可修改
//如果想让指针指向的值也不可以修改,需要声明常函数
void ShowPerson() const {
//const Type* const pointer;
//this = NULL; //不能修改指针的指向 Person* const this;
//this->mA = 100; //但是this指针指向的对象的数据是可以修改的

//const修饰成员函数,表示指针指向的内存空间的数据不能修改,除了mutable修饰的变量
this->m_B = 100;
}

void MyFunc() const {
//mA = 10000;
}

public:
int m_A;
mutable int m_B; //可修改 可变的
};


//const修饰对象 常对象
void test01() {

const Person person; //常量对象
cout << person.m_A << endl;
//person.mA = 100; //常对象不能修改成员变量的值,但是可以访问
person.m_B = 100; //但是常对象可以修改mutable修饰成员变量

//常对象访问成员函数
person.MyFunc(); //常对象只能调用const的函数

}

int main() {

test01();

system("pause");

return 0;
}

友元

1.全局函数做友元

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

#include<iostream>
#include<string>
using namespace std;
class house {
friend void gay(house* tmp);//加上这个就可以用全局函数访问类中私有属性了。
public:
house()
{
m_SittingRoom = "客厅";
m_BedRoom = "卧室";
}
string m_SittingRoom;
private:
string m_BedRoom;
};

void gay(house* tmp)
{
cout << tmp->m_SittingRoom << endl;
cout << tmp->m_BedRoom << endl;//加上就可访问。
}
int main()
{
house h;
gay(&h);
system("pause");
}

2.类做友元

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

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

class Building
{
//告诉编译器 goodGay类是Building类的好朋友,可以访问到Building类中私有内容
friend class goodGay;

public:
Building()
{
this->m_SittingRoom = "客厅";
this->m_BedRoom = "卧室";
}

public:
string m_SittingRoom; //客厅
private:
string m_BedRoom;//卧室
};

class goodGay
{
public:

goodGay()
{
building = new Building;
}
void visit()
{
cout << "好基友正在访问" << building->m_SittingRoom << endl;
cout << "好基友正在访问" << building->m_BedRoom << endl;
}

private:
Building* building;
};


void test01()
{
goodGay gg;
gg.visit();

}

int main() {

test01();

system("pause");
return 0;
}

3.成员函数做友元

这个里面有个点没搞懂,可以看下面代码中的成员函数是在类外写的,如果改为在类中写,程序会报错。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

#include<iostream>
#include<string>
using namespace std;
class Building;
class goodGay
{
public:

goodGay();
void visit(); //只让visit函数作为Building的好朋友,可以发访问Building中私有内容
void visit2();

private:
Building* building;
};


class Building
{
//告诉编译器 goodGay类中的visit成员函数 是Building好朋友,可以访问私有内容
friend void goodGay::visit();

public:
Building();

public:
string m_SittingRoom; //客厅
private:
string m_BedRoom;//卧室
};

Building::Building()
{
this->m_SittingRoom = "客厅";
this->m_BedRoom = "卧室";
}

goodGay::goodGay()
{
building = new Building;
}

void goodGay::visit()
{
cout << "好基友正在访问" << building->m_SittingRoom << endl;
cout << "好基友正在访问" << building->m_BedRoom << endl;
}

void goodGay::visit2()
{
cout << "好基友正在访问" << building->m_SittingRoom << endl;
//cout << "好基友正在访问" << building->m_BedRoom << endl;
}

void test01()
{
goodGay gg;
gg.visit();

}

int main() {

test01();

system("pause");
return 0;
}

运算符重载

1.加号运算符重载,可以用成员函数实现,也可以用全局函数实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

#include<iostream>
using namespace std;

class Person {
public:
Person(int a)
{
m_num = a;
}

Person operator+(Person &p)
{
Person temp(0);
temp.m_num = this->m_num + p.m_num;
return temp;
}
int m_num;
};


void test01()
{
Person p1(1);
Person p2(1);
//Person p3 = p1.operator+(p2);和下面表达的意思是一样的。
Person p3 = p1 + p2;
cout << p3.m_num << endl;
}
void test02()
{

}
int main()
{
test01();

system("pause");
}

2.左移运算符重载和递增运算符重载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

#include<iostream>
using namespace std;

class Person {
public:
Person(){
m_num = 0;
}


Person& operator++()
{
m_num++;
return *this;
}

Person operator++(int)
{
Person tmp=*this;
m_num++;
return tmp;

}
int m_num;
};

////注意这里的Person没用使用引用,因为上面的Person operator++(int),tmp的类型是Person。
ostream& operator<<(ostream& cout, Person p)
{
cout << p.m_num;
return cout;
}
void test01()
{
Person p1;

cout << ++p1 << endl;
cout << p1 << endl;

}
void test02()
{
Person p2;
cout << p2++ << endl;
cout << p2 << endl;
}
int main()
{
test01();
test02();
system("pause");
}

继承

继承是面向对象三大特性之一,下级的成员有上级的共性,且有自己的特性,就可以用继承来减少代码。

1.基本语法

先用不继承的方式来展示代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107

#include<iostream>
using namespace std;

class python
{
public:
void up()
{
cout << "这里是页面上方" << endl;
}
void down()
{
cout << "这里是页面下方" << endl;
}
void left()
{
cout << "这里是页面左方" << endl;
}
void right()
{
cout << "这里是页面右方" << endl;
}

void pythonvideo()
{
cout << "这里是python的视频" << endl;
}
};

class C
{
public:
void up()
{
cout << "这里是页面上方" << endl;
}
void down()
{
cout << "这里是页面下方" << endl;
}
void left()
{
cout << "这里是页面左方" << endl;
}
void right()
{
cout << "这里是页面右方" << endl;
}

void cvideo()
{
cout << "这里是C的视频" << endl;
}
};

class java
{
public:
void up()
{
cout << "这里是页面上方" << endl;
}
void down()
{
cout << "这里是页面下方" << endl;
}
void left()
{
cout << "这里是页面左方" << endl;
}
void right()
{
cout << "这里是页面右方" << endl;
}

void javavideo()
{
cout << "这里是java的视频" << endl;
}
};
int main()
{
C a;
python b;
java c;

a.down();
a.up();
a.left();
a.right();
a.cvideo();
cout << "-------------------------------" << endl;
b.down();
b.up();
b.left();
b.right();
b.pythonvideo();
cout << "-------------------------------" << endl;
c.down();
c.up();
c.left();
c.right();
c.javavideo();

system("pause");
}

可以看到,存在大量的重复代码,用继承就可以减少重复代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79

#include<iostream>
using namespace std;

class base
{
public:
void up()
{
cout << "这里是页面上方" << endl;
}
void down()
{
cout << "这里是页面下方" << endl;
}
void left()
{
cout << "这里是页面左方" << endl;
}
void right()
{
cout << "这里是页面右方" << endl;
}
};
class python :public base
{
public:

void pythonvideo()
{
cout << "这里是python的视频" << endl;
}
};

class C :public base
{
public:

void cvideo()
{
cout << "这里是C的视频" << endl;
}
};

class java :public base
{
public:

void javavideo()
{
cout << "这里是java的视频" << endl;
}
};
int main()
{
C a;
python b;
java c;

a.down();
a.up();
a.left();
a.right();
a.cvideo();
cout << "-------------------------------" << endl;
b.down();
b.up();
b.left();
b.right();
b.pythonvideo();
cout << "-------------------------------" << endl;
c.down();
c.up();
c.left();
c.right();
c.javavideo();

system("pause");
}

2.继承方式

有三种继承方式,public,private,protected、

看完这个图就差不多了。

3.继承中的对象模型

虽然父类的私有成员在子类还是无法访问,但是是会被继承下去的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

#include<iostream>
using namespace std;

class father
{
public:
int m_a;
protected:
int m_b;
private:
int m_c;
};

class son :public father
{
public:
int m_d;
};
int main()
{
//16,所以私有成员还是继承了的。
cout << sizeof(son) << endl;
}

如何看son的成员呢,用vs的工具,在菜单栏vs2019中的Developer Command Prompt。

先进入cpp的文件目录下,然后

cl /d1 reportSingleClassLayout查看的类名   所属文件名

就可以看成员结构了。

4.继承中构造和析构顺序

子类继承父类后,当创建子类对象,也会调用父类的构造函数,问题:父类和子类的构造和析构顺序是谁先谁后?

当然是有父才有子咯,而且类似于类成员中有类成员,父类都是先构造,最后析构。

5.继承同名成员,静态成员处理方式

  • 访问子类同名成员 直接访问即可
  • 访问父类同名成员 需要加作用域

静态成员还可以通过类名进行访问

6.继承多个类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

#include<iostream>
using namespace std;

class father
{
public:
int m_a=1;
};

class mather
{
public:
int m_b=0;
};

class son :public father, public mather
{
public:
int m_d;
};
int main()
{
son m;
cout << m.m_a << endl;
cout << m.m_b << endl;
}

7.菱形继承

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

#include<iostream>
using namespace std;

class grandfather
{
public:
int m_num=1;
};
class father1 :public grandfather
{};

class father2 :public grandfather
{};

class son :public father1, public father2
{
public:
int m_d;
};
int main()
{
son m;
m.father1::m_num = 2;
m.father2::m_num = 3;
cout << m.father1::m_num<< endl;
cout << m.father1::m_num << endl;
}
//2 2

可以看到,m.father1::m_num = 2; m.father2::m_num = 3;,都是指的同一个东西,导致资源浪费以及毫无意义。这时候就可以用虚继承了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

#include<iostream>
using namespace std;

class grandfather
{
public:
int m_num=1;
};
class father1 :virtual public grandfather
{};

class father2 :virtual public grandfather
{};

class son :public father1, public father2
{
public:
int m_d;
};
int main()
{
son m;
m.father1::m_num = 2;
m.father2::m_num = 3;
cout << m.father1::m_num<< endl;
cout << m.father1::m_num << endl;
}
//2 2

在继承前面加个virtual,就行了,实质就变为了用偏移,可以用vs工具去看看。

多态

c++的第三个特征,多态

多态分为两类

  • 静态多态: 函数重载 和 运算符重载属于静态多态,复用函数名
  • 动态多态: 派生类和虚函数实现运行时多态

静态多态和动态多态区别:

  • 静态多态的函数地址早绑定 - 编译阶段确定函数地址
  • 动态多态的函数地址晚绑定 - 运行阶段确定函数地址

1.多态的基本概念

多态满足条件:

  • 1、有继承关系
  • 2、子类重写父类中的虚函数

多态使用:父类指针或引用指向子类对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

#include<iostream>
using namespace std;

class Animal
{
public:
//这里加个virtual就代表虚函数,继承实际上就一个表,Dog中的同名函数会覆盖Animal的函数。
virtual void speak()
{
cout << "this is Animal" << endl;
}
};

class Dog :public Animal
{
public:
void speak()
{
cout << "this is dog" << endl;
}
};

void func(Animal& animal)//这里即使需要Animal类,但是由于继承,是可以传入dog类的
{
animal.speak();
}
//引用指向子类对象
void test01()
{
Dog dog;
func(dog);
}

//父类指针
void test02()
{
Animal* animal = new Dog;
animal->speak();
delete animal;
}
int main()
{
test01();
test02();
system("pause");
}

2.纯虚函数和抽象类

在多态中,通常父类中虚函数的实现是毫无意义的,主要都是调用子类重写的内容,因此可以将虚函数改为纯虚函数

纯虚函数语法:virtual 返回值类型 函数名 (参数列表)= 0 ;

当类中有了纯虚函数,这个类也称为==抽象类==

抽象类特点:

  • 无法实例化对象
  • 子类必须重写抽象类中的纯虚函数,否则也属于抽象类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

#include<iostream>
using namespace std;

class Father
{
public:
virtual void func() = 0;
};
class Son :public Father
{
public:
void func()
{
cout << "func函数" << endl;
}
};
void test01()
{
//Father f;//无法实例化对象
Son s;
s.func();
}

int main()
{
test01();
system("puase");
}

3.虚析构和纯虚析构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

#include<iostream>
using namespace std;

class Father
{
public:
virtual void func() = 0;

////虚析构函数
//virtual ~Father()
//{

//}

//纯虚析构函数
virtual ~Father() = 0;
};
Father::~Father()
{

}
class Son :public Father
{
public:
Son(int num)
{
m_num = new int(num);
}
void func()
{
cout << "num is " << m_num << endl;
}
~Son()
{
if (m_num != NULL)
{
delete m_num;
m_num = NULL;
cout << "son 析构函数" << endl;
}
}
int *m_num;
};
void test01()
{
Father* father = new Son(1);
delete father;
}

int main()
{
test01();
system("pause");
}

文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

#include<iostream>
#include<fstream>
#include <string>

using namespace std;

void test01(ifstream& ifs)
{
char buf[100] = { 0 };
while (ifs>>buf)
{
cout << buf << endl;
}
}

void test02(ifstream& ifs)
{
char buf[100] = { 0 };
while (ifs.getline(buf,sizeof(buf)))
{
cout << buf << endl;
}
}

void test03(ifstream& ifs)
{
string buf;
while (getline(ifs,buf))
{
cout << buf << endl;
}
}

void test04(ifstream& ifs)
{
char c;
while ((c = ifs.get()) != EOF)
{
cout << c;
}
}
int main()
{
ofstream ofs1;
ofs1.open("txt.txt", ios::trunc);
ofs1 << "姓名:张三" << endl;
ofs1 << "性别:男" << endl;
ofs1 << "年龄:18" << endl;
ofs1.close();

ifstream ifs2;
ifs2.open("txt.txt", ios::in);
if (!ifs2.is_open())
{
cout << "文件打开失败" << endl;
return 0;
}
//test01(ifs2);
//test02(ifs2);
//test03(ifs2);
test04(ifs2);
ifs2.close();
system("pause");
}

职工管理系统

跟着写了写,还不错。

workerManager.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

#pragma once
#include<iostream>
#define FILENAME "empFile.txt"
#include "worker.h"

using namespace std;

class WorkerManager
{
public:
WorkerManager();

void Showmenu();

void AddEmp();

void ShowEmp();

void GetEmpNum();

void EmptoFile();

void Savefile();

int IsExist(int id);

void DeleteEmp();

void UpdateEmp();

void FindEmp();

void SortEmp();

void ClearFile();

~WorkerManager();
int m_Empnum=0;
bool m_FileEmpty;
Worker** m_EmpArray;
};

workerManager.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450

#include "workerManager.h"
#include "employee.h"
#include "boss.h"
#include "manager.h"
#include<fstream>

WorkerManager::WorkerManager()
{
ifstream ifs;
char ch;
ifs.open(FILENAME, ios::in);
ifs >> ch;
//没有这个文件
if (!ifs.is_open())
{
m_FileEmpty = true;
m_Empnum = 0;
this->m_EmpArray = NULL;
ifs.close();
}
else if (ifs.eof())
{
m_FileEmpty = true;
m_Empnum = 0;
this->m_EmpArray = NULL;
ifs.close();
}
else
{
GetEmpNum();
EmptoFile();
}

}
WorkerManager::~WorkerManager()
{
if (m_EmpArray != NULL)
{
for (int i = 0; i < m_Empnum; i++)
{
delete m_EmpArray[i];
}
delete[] m_EmpArray;
}
}

void WorkerManager::Showmenu()
{
cout << "********************************************" << endl;
cout << "********* 欢迎使用职工管理系统! **********" << endl;
cout << "************* 0.退出管理程序 *************" << endl;
cout << "************* 1.增加职工信息 *************" << endl;
cout << "************* 2.显示职工信息 *************" << endl;
cout << "************* 3.删除离职职工 *************" << endl;
cout << "************* 4.修改职工信息 *************" << endl;
cout << "************* 5.查找职工信息 *************" << endl;
cout << "************* 6.按照编号排序 *************" << endl;
cout << "************* 7.清空所有文档 *************" << endl;
cout << "********************************************" << endl;
cout << endl;
}

void WorkerManager::AddEmp()
{
cout << "请输入要添加职工的数量" << endl;
int addnum = 0;
int i;

cin >> addnum;
if (addnum > 0)
{
int newsize = m_Empnum + addnum;
Worker** newtmp = new Worker * [newsize];
if (this->m_EmpArray != NULL)
{
for (i = 0; i < m_Empnum; i++)
{
newtmp[i] = m_EmpArray[i];
}
}

for (i = 0; i < addnum; i++)
{
int id;
string name;
int jobid;

cout << "请输入第 " << i + 1 << " 个新职工编号:" << endl;
cin >> id;

cout << "请输入第 " << i + 1 << " 个新职工名称:" << endl;
cin >> name;

cout << "请选择该职工的岗位:" << endl;
cout << "1、普通职工" << endl;
cout << "2、经理" << endl;
cout << "3、老板" << endl;
cin >> jobid;

Worker* worker = NULL;
switch (jobid)
{
case 1:
worker = new Employee(id, name, jobid);
break;
case 2:
worker = new Manager(id, name, jobid);
break;
case 3:
worker = new Boss(id, name, jobid);
break;
default:
break;
}

newtmp[m_Empnum + i] = worker;
}
delete this->m_EmpArray;
this->m_EmpArray = NULL;
this->m_EmpArray = newtmp;
this->m_Empnum = newsize;
m_FileEmpty = false;
cout << "成功添加" << addnum << "名新职工!" << endl;
}
else
{
cout << "输入有错" << endl;
}
Savefile();
system("pause");
system("cls");
}

void WorkerManager::ShowEmp()
{
if (this->m_Empnum==0)
{
cout << "没有一个职工" << endl;
}
else
{
int i;
for (i = 0; i < m_Empnum; i++)
{
this->m_EmpArray[i]->showInfo();
}
}

system("pause");
system("cls");
}

void WorkerManager::GetEmpNum()
{
ifstream ifs;
ifs.open(FILENAME, ios::in);
int id;
string name;
int jobid;

while (ifs >> id && ifs >> name && ifs >> jobid)
{
m_Empnum++;
}
ifs.close();
}

void WorkerManager::EmptoFile()
{
ifstream ifs;
ifs.open(FILENAME, ios::in);
int id;
int i=0;
string name;
int jobid;
Worker** newtmp = new Worker * [m_Empnum];
while (ifs >> id && ifs >> name && ifs >> jobid)
{
Worker* worker = NULL;
if (jobid == 1)
{
worker = new Employee(id, name, jobid);
}
else if (jobid == 2)
{
worker = new Manager(id, name, jobid);
}
else
{
worker = new Boss(id, name, jobid);
}

newtmp[i] = worker;
i++;
}
this->m_EmpArray = newtmp;
m_FileEmpty = false;
ifs.close();
}
void WorkerManager::Savefile()
{
int i;
ofstream ofs;
ofs.open(FILENAME, ios::out);
for (i = 0; i < m_Empnum; i++)
{
ofs << this->m_EmpArray[i]->m_Id << " "
<< this->m_EmpArray[i]->m_Name << " "
<< this->m_EmpArray[i]->m_JobId << endl;
}
ofs.close();
}

int WorkerManager::IsExist(int id)
{
int i;
for (i = 0; i < m_Empnum; i++)
{
if (m_EmpArray[i]->m_Id == id)
{
return i;
}
}
return -1;
}

void WorkerManager::DeleteEmp()
{
if (this->m_FileEmpty)
{
cout << "文件不存在或记录为空!" << endl;
}
else
{
int id;
int index;
int i;

cout << "请输入你要删除的职工编号" << endl;
cin >> id;
index = IsExist(id);

if (index != -1)
{
for (i = index; i < m_Empnum-1; i++)
{
m_EmpArray[i] = m_EmpArray[i + 1];
}
m_Empnum--;
Savefile();
cout << "删除成功" << endl;
}
else
{
cout << "没有查到该职员" << endl;
}

}

system("pause");
system("cls");

}

void WorkerManager::UpdateEmp()
{
if (this->m_FileEmpty)
{
cout << "文件不存在或记录为空!" << endl;
}
else
{
int id;
int index;
int i;

cout << "请输入你要修改的职工编号" << endl;
cin >> id;
index = IsExist(id);

if (index != -1)
{
int newid;
string newname;
int newjobid;

cout << "请输入修改的新职工编号:" << endl;
cin >> newid;

cout << "请输入修改的新职工名称:" << endl;
cin >> newname;

cout << "请修改该职工的岗位:" << endl;
cout << "1、普通职工" << endl;
cout << "2、经理" << endl;
cout << "3、老板" << endl;
cin >> newjobid;
m_EmpArray[index]->m_Id = newid;
m_EmpArray[index]->m_Name = newname;
m_EmpArray[index]->m_JobId = newjobid;

Savefile();
cout << "修改成功" << endl;
}
else
{
cout << "没有查到该职员" << endl;

}
}
system("pause");
system("cls");
}

void WorkerManager::FindEmp()
{
if (this->m_FileEmpty)
{
cout << "文件不存在或记录为空!" << endl;
}
else
{
int id;
int index;

cout << "请输入你要查找的职工编号" << endl;
cin >> id;
index = IsExist(id);

if (index != -1)
{
this->m_EmpArray[index]->showInfo();
}
else
{
cout << "没有查到该职员" << endl;
}
}

system("pause");
system("cls");
}

void WorkerManager::SortEmp()
{
if (this->m_FileEmpty)
{
cout << "文件不存在或记录为空!" << endl;
}
else
{

cout << "请选择排序方式: " << endl;
cout << "1、按职工号进行升序" << endl;
cout << "2、按职工号进行降序" << endl;

int select = 0;
cin >> select;

if (select==1)
{
//冒泡排序
int i, j;
Worker* tmp = NULL;
for (i = 0; i < m_Empnum; i++)
{
for (j = 0; j < m_Empnum - 1; j++)
{
if (m_EmpArray[j]->m_Id > m_EmpArray[j + 1]->m_Id)
{
tmp = m_EmpArray[j + 1];
m_EmpArray[j + 1] = m_EmpArray[j];
m_EmpArray[j] = tmp;
}
}
}
Savefile();
cout << "排序成功" << endl;
}
else if (select == 2)
{
//选择排序
int i, j, k;
Worker* tmp = NULL;
for (i = 0; i < m_Empnum; i++)
{
k = i;
for (j = i + 1; j < m_Empnum; j++)
{
if (m_EmpArray[j]->m_Id > m_EmpArray[k]->m_Id)
{
k = j;
}
}
if (k != i)
{
tmp = m_EmpArray[i];
m_EmpArray[i] = m_EmpArray[k];
m_EmpArray[k] = tmp;
}
}
Savefile();
cout << "排序成功" << endl;
}
else
{
cout << "选择有误" << endl;
}

}

system("pause");
system("cls");
}

void WorkerManager::ClearFile()
{
cout << "确认清空?" << endl;
cout << "1、确认" << endl;
cout << "2、返回" << endl;

int select = 0;
cin >> select;

if (select == 1)
{
ofstream ofs(FILENAME, ios::trunc);
ofs.close();

if (m_EmpArray != NULL)
{
for (int i = 0; i < m_Empnum; i++)
{
delete m_EmpArray[i];
}
delete[] m_EmpArray;
m_EmpArray = NULL;
m_Empnum = 0;
m_FileEmpty = true;
}
system("pause");
system("cls");
}
else if (select == 2)
{
system("pause");
system("cls");
}
}

worker.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

#pragma once
#include<iostream>
#include<string>
using namespace std;

class Worker
{
public:
//一个抽象类
virtual void showInfo() = 0;
virtual string getJobName() = 0;

int m_Id;
string m_Name;
int m_JobId;
};

employee.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

#pragma once
#include<iostream>
#include<string>
#include"worker.h"
using namespace std;

class Employee :public Worker
{
public:
Employee(int Id, string Name, int JobId);

virtual void showInfo();
virtual string getJobName();

};

employee.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

#include "employee.h"

Employee::Employee(int Id, string Name, int JobId)
{
this->m_Id = Id;
this->m_Name = Name;
this->m_JobId = JobId;
}

void Employee::showInfo()
{
cout << "职工编号: " << this->m_Id
<< " \t职工姓名: " << this->m_Name
<< " \t岗位:" << this->getJobName()
<< " \t岗位职责:完成经理交给的任务" << endl;
}

string Employee::getJobName()
{
return string("员工");
}

manager.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

#pragma once
#include<iostream>
#include<string>
#include"worker.h"
using namespace std;

class Manager :public Worker
{
public:
Manager(int Id, string Name, int JobId);

virtual void showInfo();
virtual string getJobName();

};

manager.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

#include "manager.h"

Manager::Manager(int Id, string Name, int JobId)
{
this->m_Id = Id;
this->m_Name = Name;
this->m_JobId = JobId;
}

void Manager::showInfo()
{
cout << "职工编号: " << this->m_Id
<< " \t职工姓名: " << this->m_Name
<< " \t岗位:" << this->getJobName()
<< " \t岗位职责:完成老板交给的任务" << endl;
}

string Manager::getJobName()
{
return string("经理");
}

boss.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

#pragma once
#include<iostream>
#include<string>
#include"worker.h"
using namespace std;

class Boss :public Worker
{
public:
Boss(int Id, string Name, int JobId);

virtual void showInfo();
virtual string getJobName();

};

boss.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

#include "boss.h"

Boss::Boss(int Id, string Name, int JobId)
{
this->m_Id = Id;
this->m_Name = Name;
this->m_JobId = JobId;
}

void Boss::showInfo()
{
cout << "职工编号: " << this->m_Id
<< " \t职工姓名: " << this->m_Name
<< " \t岗位:" << this->getJobName()
<< " \t岗位职责:管理所有职工" << endl;
}

string Boss::getJobName()
{
return string("老板");
}

main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

#include<iostream>
#include<string>
#include "workerManager.h"

using namespace std;

int main()
{
WorkerManager wm;
int choice=0;

while (1)
{
wm.Showmenu();
cout << "请输入您的选择:" << endl;
cin >> choice;
switch (choice)
{
case 0: //退出系统
exit(0);
case 1: //添加职工
wm.AddEmp();
break;
case 2: //显示职工
wm.ShowEmp();
break;
case 3: //删除职工
wm.DeleteEmp();
break;
case 4: //修改职工
wm.UpdateEmp();
break;
case 5: //查找职工
wm.FindEmp();
break;
case 6: //排序职工
wm.SortEmp();
break;
case 7: //清空文件
wm.ClearFile();
break;
default:
system("cls");
break;
}
}
system("pause");
}