C++学习笔记
馨er BOSS

C++学习笔记

1 C++对C的增强

1、定义函数时必须写明类型,即int不可省略

2、声明结构体类型后,定义结构体变量时,C中需写struct,C++则不需要

3、全局变量重定义的加强(随用随定义)

4、布尔类型的增强

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include<iostream>

using namespace std;

int main() {
bool flag = true;
cout << "flag=" << flag << endl;
flag = false;
cout << "flag=" << flag << endl;
flag = 100;
cout << "flag=" << flag << endl;
return 0;
}
//bool类型的字节数为1
  • bool只能取0,1,非0自动转换为1,值只能为true和false

5、三目运算符的增强

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>

using namespace std;

int main() {
int a = 10,b = 20;
int c;
c = a < b ? a : b;
cout << "c=" << c << endl;
(a < b ? a : b) = 50;
//*((a < b) ? &a : &b) = 50;(C,C++通用写法)
cout << "a=" << a << endl;
return 0;
}
  • C++中三目运算符可以做左值,C中三目运算符不能做左值

  • C++中三目运算符返回变量自身,C中返回变量的值

  • C++中两种赋值同时出现时,不论谁前谁后,都是*((a < b) ? &a : &b) = 50的结果优先

6、const的增强

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>

using namespace std;

int main() {
const int a = 10;
int* b = (int*)&a;
*b = 50;
//改变的为临时开辟的变量
cout << a << endl;
cout << *b << endl;
return 0;
}
  • C++中通过指针不能改变所指向常变量的值

  • C++中将const存于符号表中,无空间和地址

  • C++中const定义的为常量(与#define类似,但运行时段不同,define无法被输出)

7、枚举类型的增强

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>

using namespace std;

enum season {
SPR = 0,
SUM,
AUT,
WIN
};
int main() {
//enum season s=2;(×)
enum season s = AUT;
cout << s << endl;
return 0;
}

C++中枚举变量赋值只能赋左边的元素名,不能赋数字

2 命名空间(namespace)

2.1 命名空间的使用

方式一

1
2
3
4
5
6
7
8
9
10
#include <iostream>

using namespace std;

int main() {
int a;
cin >> a;
cout << "a=" << a << endl;
return 0;
}

方式二
1
2
3
4
5
6
7
8
#include <iostream>

int main(){
int a;
std::cin >> a;
std::cout << "a=" << a << std::endl;
return 0;
}

方式三
1
2
3
4
5
6
7
8
9
10
#include <iostream>
using std::cout;
using std::endl;
using std::cin;
int main(){
int a;
cin >> a;
cout << "a=" << a << endl;
return 0;
}

  • 命名空间更好的控制标识符的作用域

  • cout代表黑屏幕,cin代表键盘

  • iostream提供一个叫命名空间的东西,标准的命名空间是std

2.2 命名空间的定义

2.2.1 命名空间的普通定义

方式一

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>

using namespace std;

namespace spaceA {
int g_a = 10;
}

int main() {
cout << spaceA::g_a << endl;
return 0;
}

方式二
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>

using namespace std;

namespace spaceA {
int g_a = 10;
}

int main() {
using namespace spaceA;
cout << g_a << endl;
return 0;
}

方式三
1
2
3
4
5
6
7
8
9
10
#include <iostream>
using namespace std;
namespace spaceA {
int g_a = 10;
}
int main() {
using spaceA::g_a;
cout << g_a << endl;
return 0;
}

2.2.2 命名空间的嵌套定义

方式一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>

using namespace std;

namespace spaceB {
int a = 20;
namespace spaceC {
struct teacher {
int id;
char name[64];
};
}
}

int main() {
using namespace spaceB::spaceC;
struct teacher t1;
t1.id = 10;
cout << "" << t1.id << endl;
return 0;
}

方式二
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
using namespace std;
namespace spaceB {
int a = 20;
namespace spaceC {
struct teacher {
int id;
char name[64];
};
}
}
int main() {
spaceB::spaceC::teacher t1;
t1.id = 10;
cout << "" << t1.id << endl;
return 0;
}

方式三
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>

using namespace std;

namespace spaceB {
int a = 20;
namespace spaceC {
struct teacher {
int id;
char name[64];
};
}
}

int main() {
using spaceB::spaceC::teacher;
teacher t1;
t1.id = 10;
cout << "" << t1.id << endl;
return 0;
}

3 内联函数

原理:内联函数直接将代码贴到函数调用的地方,使得程序在调用函数时不用来回跳跃等其它操作,从而达到提高程序运行速度的目的(但其占用内存更大)

  • 适用场景:函数体很“小”,且被“频繁”调用
  • inline和宏定义的区别:inline函数是函数,宏不是函数;内联函数在编译时展开,宏是在编译时展开的;在编译的时候,内联函数可以直接被镶嵌到目标代码中,宏定义只是简单地做文本替换;内联函数可以完成类型检查、语句是否正确等编译功能,宏不具备这样的能力;宏定义在处理宏参数时要非常小心,容易产生二义性,而内联函数定义时不会产生二义性
  • C++中内联编译的限制:不能存在任何形式的循环语句,函数体不能过于庞大,不能对函数进行取址操作,函数内联声明必须在调用语句之前

在类定义中的定义的函数都是内联函数,即使没有使用 inline 说明符。对内联函数进行任何修改,都需要重新编译函数的所有客户端,因为编译器需要重新更换一次所有的代码,否则将会继续使用旧的函数。如果已定义的函数多于一行,编译器会忽略 inline 限定符(即看作普通函数处理)

注意:定义为普通函数,声明为内联函数,仍为普通函数

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
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>

using namespace std;

#define MAX(a,b)
((a)>(b)?(a):(b))

int max(int a, int b) {
return (a > b) ? a : b;
}

inline void printAB(int a, int b) {
cout << "a = " << a << ",b = " << b << endl;
}

int main() {
int a = 10;
int b = 20;
int c = 0;
c = MAX(a, b);
cout << "c = " << c << endl;
cout << "------------" << endl;
#if 1
for (int i = 0; i < 1000; i++) {
a++;
b++;
printAB(a, b);
}
#endif
return 0;
}
// 计算机内存由慢到快网盘,硬盘,内存,缓存,寄存器

4 默认参数和占位参数

4.1 单个默认参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>

using namespace std;

void func(int a = 666) {
cout << "a = " << a << endl;
}

int main() {
int value = 10;
func();
// 这个不填参数的时候,会使用你的默认参数,填参数时,使用你填的
return 0;
}

4.2 多个默认参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>

using namespace std;

int get_volume(int len, int width, int height) {
cout << "len = " << len << endl;
cout << "w = " << width << endl;
cout << "h = " << height << endl;
return len * width * height;
}
int main() {
int len = 10;
int w = 20;
int h = 30;
cout << "体积是" << get_volume(len, w, h) << endl;
return 0;
}
// 参数个数一一对应
// 传参从右往左传,可以一部分为默认参数,一部分传参

默认参数为当没有实参时,默认的值。 当函数有一个参数为默认参数,那么从这个参数起,后面的参数都必须有默认参数。在函数的声明和定义中,默认参数只能写一次,不然编译器会报错,特别是在分文件编写中

4.3 占位参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>

using namespace std;

void func1(int x, int = 0) {
cout << "x = " << x << endl;
}

void func2(int x, int) {
cout << "x = " << x << endl;
}

int main() {
func1(200);
func2(199, 10);
return 0;
}

占位参数只有参数类型声明,而没有参数名声明,一般情况下,在函数体内部无法使用占位参数。占位参数必须填入实参,占位参数也可以有默认值。占位参数与默认参数结合起来使用,兼容C语言程序中可能出现的不规范写法。

5 函数重载

5.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
#include <iostream>

using namespace std;

int func(int a, int b) {
cout << "func1" << endl;
return 0;
}

char func(int a, char b) {
cout << "func2" << endl;
return 0;
}

// 如果是函数重载的话不要写默认参数,为了避免调用出现函数冲突
// 可以写占用参数,但不要与默认参数一起使用
// 如果调用func(10,20)则出错
int func(int a, int b, int c = 300) {
cout << "func3" << endl;
return 0;
}

void print1(int a) {
cout << "print1" << endl;
cout << "a = " << a << endl;
}

void print1(double b) {
cout << "print2" << endl;
cout << "b = " << b << endl;
}

int main() {
char x = 'a';
func(10, 20, 30);
func(10, x);
print1(10);
print1(10.0);
print1(3.14f);// (double)
print1('a');//(int)
// 匹配类型优先,其次为隐式转换
// 若都匹配不到,则调用失败
return 0;
}

函数名相同,参数列表(个数,类型,顺序)不同;函数返回值并不是构成函数重载的条件

5.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
#include <iostream>

using namespace std;

int func(int a, int b) {
cout << "func(int,int)" << endl;
return 0;
}

int func(int a, int b,int c) {
cout << "func(int,int,int)" << endl;
return 0;
}

// 1.定义一种函数类型
typedef int(MY_FUNC)(int, int);


// 2.定义一个指向一种函数类型的指针
typedef int(*MY_FUNC_P)(int, int);

int main() {
// 1
MY_FUNC* fp = NULL;
fp = func;
fp(10, 20);
// 2
MY_FUNC_P fp1 = NULL;
fp1 = func;
fp1(10, 20);
// 3
int (*fp3)(int, int) = NULL;
fp3 = func;
fp3(10, 30);

func(10, 20);
func(10, 20, 30);
fp3 = func;//fp3->func(int,int)

// 函数指针不可自加
// 实际上在给函数指针赋值的时候,是会发生函数重载匹配的
// 在调用函数指针的时候,所调用的函数就已经固定了,而非重载,此处不能隐式转换
int(*fp4)(int, int, int) = NULL;
fp4 = func;//fp4->func(int,int,int)

fp3(10, 30);//func(int,int)
fp3(10, 20);
fp4(10, 30, 20);

return 0;
}

6 类与对象

6.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
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>

using namespace std;

struct Hero {
char name[64];
int sex;
};

void printHero(struct Hero& h) {
cout << "Hero" << endl;
cout << "name = " << h.name << endl;
cout << "sex = " << h.sex << endl;
}

class AdvHero {
public:// 访问控制权限
char name[64];
int sex;
void printHero() {
cout << "advHero" << endl;
cout << "name = " << name << endl;
cout << "sex = " << sex << endl;
}
};

class Animal {
// {}以内叫类的内部,以外叫类的外部
public:
char kind[64];
char color[64];
// 在public下面定义成员变量和函数 是能够在类的内部和外部都可以访问的
void printAnimal() {
cout << "kind = " << kind << endl;
cout << "color = " << color << endl;
}
void write() {
cout << kind << "开始写字了" << endl;
}

void run() {
cout << kind << "跑起来了" << endl;
}
private:
// 在private下面定义的成员变量和方法只能够在类的内部访问
#if 0
char kind[64];
char color[64];
#endif
};

int main() {
Hero h;
strcpy(h.name, "gailun");
h.sex = 1;
printHero(h);
AdvHero advH;
strcpy(advH.name, "ChunBro");
advH.sex = 1;
advH.printHero();
cout << "------------" << endl;
Animal dog;
strcpy(dog.kind, "dog");
strcpy(dog.color, "yellow");
Animal sheep;
strcpy(sheep.kind, "sheep");
strcpy(sheep.color, "white");
dog.write();
sheep.run();
return 0;
}

6.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
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
#include <iostream>

using namespace std;

struct Date {
int year;
int month;
int day;
};

void init_date(struct Date& d) {
cout << "year, month, day" << endl;
cin >> d.year;
cin >> d.month;
cin >> d.day;
}

// 打印data的接口
void print_date(struct Date& d) {
cout << d.year << "年" << d.month << "月" << d.day << "日" << endl;
}

bool is_leap_year(struct Date& d) {
if ((d.year % 4 == 0) && (d.year % 100 != 0) || (d.year % 400 == 0)) {
return true;
}
return false;
}

class MyDate {
public:
// 成员方法 成员函数
void init_date() {
cout << "year, month, day" << endl;
cin >> year;
cin >> month;
cin >> day;
}

// 打印data的接口
void print_date() {
cout << year << "年" << month << "月" << day << "日" << endl;
}

bool is_leap_year() {
if ((year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0)) {
return true;
}
return false;
}

int get_year() {
return year;
}

void set_year(int new_year) {
year = new_year;
}

protected:// 保护控制权限。在类的继承中跟private有区别,在单个类中,跟private是一模一样的
private:
int year;
int month;
int day;
};

// 一个类类的内部,默认的访问控制权限是private
class Hero {
int year;
};

// 一个结构体默认的访问控制权限是public
struct Hero2 {
int year;
void print() {

}
};

int main() {
#if 0
Date d1;
init_date(d1);
print_date(d1);
if (is_leap_year(d1) == true) {
cout << "是闰年" << endl;
}
else {
cout << "不是闰年" << endl;
}
#endif
cout << "--------------" << endl;
MyDate my_date;
my_date.init_date();
my_date.print_date();
if (my_date.is_leap_year() == true) {
cout << "是闰年" << endl;
}
else {
cout << "不是闰年" << endl;
}
// getter,setter
cout << my_date.get_year() << endl;
my_date.set_year(2000);
cout << my_date.get_year() << endl;

/*错误写法:
Hero h;
h.year = 1000;*/
Hero2 h2;
h2.year = 100;
return 0;
}

6.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
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;

class Dog {
public:
void eat(char *food) {
cout << name << "吃" << food << endl;
}
char name[64];
};

// 面向过程
void eat(class Dog &dog, char *food) {
cout << dog.name << "吃" << food << endl;
}

int main(void) {
Dog dog;
strcpy(dog.name, "狗");
eat(dog, "翔");
dog.eat("翔");
return 0;
}

6.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
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
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>

using namespace std;

// 圆的周长
double getCircleGirth(double r) {
return 2 * 3.14*r;
}

// 圆的面积
double getCircleArea(double r) {
return 3.14*r*r;
}

// 用面向对象实现
// 圆类
class Circle {
public:
void setR(double r) {
m_r = r;
}

double getR() {
return m_r;
}

double getGirth() {
return 2 * 3.14 *m_r;
}

double getArea() {
return m_r*m_r*3.14;
}

private:
double m_r; // 圆的私有成员 半径
};

class Circle2 {
public:

void setR(double r) {
m_r = r;
}

double getR() {
return m_r;
}

double getArea() {
m_area = m_r*m_r*3.14;
return m_area;
}

double getGirth() {
m_girth = m_r * 2 * 3.14;
return m_girth;
}

private:
double m_r;
double m_girth; //周长
double m_area;//面积
};


int main(void) {
double r = 10; // 圆的半径
double g = 0;
double a = 0;
g = getCircleGirth(r);
a = getCircleArea(r);
cout << "圆的半径是" << r << endl;
cout << "圆的周长是" << g << endl;
cout << "圆的面积是" << a << endl;

cout << "------" << endl;

Circle c;

c.setR(10);
cout << "圆的半径是" << c.getR() << endl;
cout << "圆的周长是" << c.getGirth() << endl;
cout << "圆的面积是" << c.getArea() << endl;
cout << "------------" << endl;
Circle2 c2;

c2.setR(10);
cout << "圆的半径是" << c2.getR() << endl;
cout << "圆的周长是" << c2.getGirth() << endl;
cout << "圆的面积是" << c2.getArea() << endl;
return 0;
}

案例二:求圆的面积(多文件)

main.cpp

1
2
3
4
5
6
7
8
9
10
11
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include "Circle.h"
using namespace std;

int main(void) {
Circle c;
c.setR(10);
cout << "面积" << c.getArea() << endl;
return 0;
}

Circle.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include "Circle.h"

void Circle::setR(double r) {
m_r = r;
}

double Circle::getR() {
return m_r;
}

double Circle::getArea() {
m_area = m_r *m_r *3.14;
return m_area;
}

double Circle::getGirth() {
m_girth = m_r * 2 * 3.14;

return m_girth;
}

案例三:求立方体是否相等

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
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>

using namespace std;

// 立方体类
class Cube {
public:
void setABC(int a, int b, int c) {
m_a = a;
m_b = b;
m_c = c;
}

int getArea() {
return (m_a*m_b) * 2 + (m_a*m_c) * 2 + (m_b*m_c) * 2;
}

int getVolume() {
return (m_a*m_b*m_c);
}

int getA() {
return m_a;
}

int getB() {
return m_b;
}

int getC() {
return m_c;
}

// 同类之间无私处
bool judgeCube(Cube &another) {
if (m_a == another.m_a &&
m_b == another.getB() &&
m_c == another.getC()) {
return true;
}
else {
return false;
}
}
private:
int m_a;
int m_b;
int m_c;
};

// 全局函数
bool judgeCube(Cube &c1, Cube &c2) {
if (c1.getA() == c2.getA() &&
c1.getB() == c2.getB() &&
c1.getC() == c2.getC()) {
return true;
}
else {
return false;
}
}

int main(void) {
Cube c1;
c1.setABC(10, 20, 30);

Cube c2;
c2.setABC(10, 20, 30);

cout << "c1 的体积是" << c1.getVolume() << endl;
cout << "c1 的面积是" << c1.getArea() << endl;

if (judgeCube(c1, c2) == true) {
cout << "相等" << endl;
}
else {
cout << "不相等" << endl;
}
cout << " ------ " << endl;
if (c1.judgeCube(c2) == true) {
cout << "相等" << endl;
}
else {
cout << "不相等" << endl;
}
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
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
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;

// 点类
class Point {
public:
void setXY(int x, int y) {
m_x = x;
m_y = y;
}

int getX() {
return m_x;
}

int getY() {
return m_y;
}
private:
int m_x;
int m_y;
};

// 圆类
class Circle {
public:
void setXY(int x, int y) {
x0 = x;
y0 = y;
}

void setR(int r) {
m_r = r;
}

// 提供一个判断点是否在圆内
// true 在内部
// false 在外部
bool judgePoint(Point &p) {
int dd;

dd = (p.getX() - x0)*(p.getX() - x0) + (p.getY() - y0)*(p.getY() - y0);

if (dd > m_r*m_r) {
return false;
}
else {
return true;
}
}

private:
int x0;
int y0;
int m_r;
};

int main(void) {
Circle c;
c.setXY(2, 2);
c.setR(4);

Point p;
p.setXY(8, 8);
if (c.judgePoint(p) == true) {
cout << "圆的内部" << endl;
}
else {
cout << "圆的外部" << endl;
}
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
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
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cmath>
using namespace std;

// 点类
class Point {
public:
void setXY(int x, int y) {
m_x = x;
m_y = y;
}

// 计算两点距离的方法
double pointDistance(Point &another) {
int d_x = m_x - another.m_x;
int d_y = m_y - another.m_y;
double dis = sqrt(d_x*d_x + d_y*d_y);
return dis;
}
private:
int m_x;
int m_y;
};

class Circle {
public:
void setR(int r) {
m_r = r;
}

void setXY(int x, int y) {
p0.setXY(x, y);
}

// 判断圆是否跟我相交
bool isIntersection(Circle &another) {
// 两个半径之和
int rr = m_r + another.m_r;
// 两圆心之间距离
double dis = p0.pointDistance(another.p0);
if (dis <= rr) {
// 相交
return true;
}
else {
return false;
}
}
private:
int m_r;
Point p0;
};

int main(void) {
Circle c1, c2;
int x, y, r;
cout << "请输入第一个圆的半径" << endl;
cin >> r;
c1.setR(r);
cout << "请输入第一个圆的x" << endl;
cin >> x;
cout << "请输入第一个圆的y" << endl;
cin >> y;
c1.setXY(x, y);
cout << "请输入第2个圆的半径" << endl;
cin >> r;
c2.setR(r);
cout << "请输入第2个圆的x" << endl;
cin >> x;
cout << "请输入第2个圆的y" << endl;
cin >> y;
c2.setXY(x, y);
if (c1.isIntersection(c2) == true) {
cout << "相交" << endl;
}
else {
cout << "不相交" << endl;
}
return 0;
}

7 类中的函数

7.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
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>

using namespace std;

class Test {
public:
#if 0
void init(int x, int y) {
m_x = x;
m_y = y;
}
#endif

// test类的构造函数
// 在对象被创建的时候,用来初始化对象的函数
Test() { // 无参数的构造函数
m_x = 0;
m_y = 0;
}
Test(int x, int y) {
m_x = x;
m_y = y;
name = (char*)malloc(100);
strcpy(name, "zhang3");
}

Test(int x) {
m_x = x;
m_y = 0;
}

void prinT() {
cout << "x = " << m_x << " y = " << m_y << endl;
}

// 析构函数
// 析构函数可以释放一些不必要的东西
~Test() {
cout << "~Test()..." << endl;
if (name != NULL) {
free(name);
cout << "free sycc!" << endl;
}
}

void test1() {
Test t1(10, 20);
t1.prinT();
// 在一个对象临死之前,要自动调用析构函数
}

private:
int m_x;
int m_y;
char* name;
};

int main() {
// Test t1;
// t1.init(10, 20);
// (普通类函数定义对象的写法)
// t1此时是未知的,最好初始化
Test t1(10, 20);
t1.prinT();
Test t2(100);
t2.prinT();
Test t3;// 调用类的无参数构造函数
t3.prinT();
return 0;
}
// 构造函数可以被重载
// 析构函数不可以被重载,析构函数只有一个

构造函数和析构函数都没有返回值,析构函数没有形参

7.2 构造函数的分类

7.2.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
#include <iostream>

using namespace std;

class Test {
public:
#if 0
Test() {

}
#endif// 默认的,无作用
// 默认的无参构造函数
void prinT() {
cout << "x = " << m_x << "y = " << m_y << endl;
}

// 显示提供一个有参的构造函数
// 默认的无参 构造函数就不复存在
Test(int x, int y) {
m_x = x;
m_y = y;
}
Test() {
m_x = 0;
m_y = 0;
}

//默认的析构函数
#if 0
~Test() {

}
#endif
private:
int m_x;
int m_y;
};

int main() {
Test t1;// 调用Test无参构造
t1.prinT();
return 0;
}

7.2.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
#include <iostream>

using namespace std;

class Test {
public:
Test() {
m_x = 0;
m_y = 0;
}
Test(int x, int y) {
m_x = x;
m_y = y;
}

void prinT() {
cout << "x = " << m_x << ",y = " << m_y << endl;
}

#if 0
// 显示的拷贝构造函数
Test(const Test& another) {
cout << "Test(const Test &)..." << endl;
m_x = another.m_x;
m_y = another.m_y;
}
#endif
#if 0
// 会有一个默认的拷贝构造函数
Test(const Test& another) {
m_x = another.m_x;
m_y = another.m_y;
}
#endif
#if 0
// =赋值操作符
void operator=(const Test& another) {
m_x = another.m_x;
m_y = another.m_y;
}
#endif

private:
int m_x;
int m_y;
};

int main() {
Test t1(100, 200);
Test t2(t1);
t2.prinT();
Test t3 = t1;
// 依然是初始化t2的时候调用t3拷贝构造函数
Test t4;
t4 = t1;
// 调用的不是t4的拷贝构造函数,而是t4的赋值操作符函数
return 0;
}

7.2.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
#include <iostream>

using namespace std;

class A {
public:
A() {
m_a = 0;
m_b = 0;
}

A(const A& another) {
m_a = another.m_a;
m_b = another.m_b;
cout << "A(const A&...)" << endl;
}
private:
int m_a;
int m_b;
};

// 类中
// 会有个默认的无参构造函数:
// 当没有任何显示的构造函数(显示的无参,显示有参,显示拷贝构造)的时候,默认无参构造函数就会出现
// 会有默认的拷贝构造:
// 当没有显示的拷贝构造函数,默认的拷贝构造就会出现
// 会有默认的析构函数:
// 当没有显示的析构函数的时候,默认的析构函数就会出现

int main() {
A a;
A a1(a);
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
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
#include <iostream>

using namespace std;

class Test {
public:
Test() {
cout << "Test()..." << endl;
m_x = 0;
m_y = 0;
}
Test(int x, int y) {
cout << "Test(int x,int y)..." << endl;
m_x = x;
m_y = y;
}

Test(const Test& another) {
cout << "Test(const Test &)..." << endl;
m_x = another.m_x;
m_y = another.m_y;
}

void operator=(const Test& another) {
cout << "operator=(const Test &)" << endl;
m_x = another.m_x;
m_y = another.m_y;
}

void prinT() {
cout << "x = " << m_x << " y = " << m_y << endl;
}

~Test() {
cout << "~Test()..." << endl;
}

private:
int m_x;
int m_y;
};

// 析构函数调用的顺序,跟构造相反,谁先构造的,谁后析构
void test1() {
Test t1(10, 20);
Test t2(t1);// Test t2 = t1;
}

void test2() {
Test t1(10, 20);
Test t2;
t2 = t1;// =操作符
}

void func(Test t) { // Test t = t1;Test t的拷贝构造函数
cout << "func begin..." << endl;
t.prinT();
cout << "func end..." << endl;
}

void test3() {
cout << "test3 begin..." << endl;
Test t1(10, 20);
func(t1);
cout << "test3 end..." << endl;
}

Test func2() {
cout << "func2 begin..." << endl;
Test temp(10,20);
temp.prinT();
cout << "func2 end..." << endl;
return temp;
}// 匿名的对象 = temp(构造)
// 一次析构

void test4() {
cout << "test4 begin..." << endl;
func2();// 返回一个匿名对象
// 当一个函数返回一个匿名对象的时候,
// 函数外部没有任何变量去接收它
// 这个匿名对象将不会再被使用,
// 编译器会直接将这个匿名对象回收掉,
// 而不是等待整个函数执行完毕再回收
// 故此处有两次析构
cout << "test4 end..." << endl;
}

void test5() {
cout << "test5 begin..." << endl;
Test t1 = func2();
// 不会触发t1的拷贝构造,而是将匿名对象转正t1
// 把这个匿名对象起了名字叫做t1
cout << "test5 end..." << endl;
}

void test6() {
cout << "test6 begin..." << endl;
Test t1;// t1已经被初始化了
t1 = func2();//不会被转正
// 仍然是匿名对象,t1会调用等号操作符
// t1.operator=匿名对象
// 编译器会立刻回收匿名对象
t1.prinT();
cout << "test6 end..." << endl;
}

int main() {
//test1();
//test2();
//test3();
//test4();
//test5();
test6();
return 0;
}

7.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
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>

using namespace std;

class Teacher {
public:
Teacher(int id, const char* name) {
cout << "Teacher(int,char*)..." << endl;
m_id = id;
int len = strlen(name);
m_name = (char*)malloc(len + 1);
strcpy(m_name, name);
}

void prinT() {
cout << "id = " << m_id << ",name = " << m_name << endl;
}

// 显示的提供一个拷贝构造函数,来完成深拷贝动作
Teacher(const Teacher& another) {
m_id = another.m_id;
// 深拷贝动作
int len = strlen(another.m_name);
m_name = (char*)malloc(len + 1);// 一定要释放,且释放一次
strcpy(m_name, another.m_name);
}

~Teacher() {
cout << "~Teacher()..." << endl;
if (m_name != NULL) {
free(m_name);
m_name = NULL;
}
}

private:
int m_id;
char* m_name;
};

void test() {
Teacher t1(1, "zhang3");
t1.prinT();
Teacher t2(t1);// t2的默认拷贝构造
t2.prinT();
}

int main() {
test();
return 0;
}

7.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
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
#include <iostream>

using namespace std;

class A {
public:
A(int a) {
cout << "A()..." << a << endl;
m_a = a;
}

~A() {
cout << "~A()..." << m_a << endl;
}

void printA() {
cout << "a = " << m_a << endl;
}

private:
int m_a;
};

// 构造函数的初始化列表
class B {
public:
B(A &a1,A &a2,int b) :m_a1(a1),m_a2(a2) {
cout << "B(A&,A&,int)..." << endl;
m_b = b;
}

// 构造对象成员的顺序跟初始化列表的顺序无关
// 而是与对象的定义顺序有关
B(int a1, int a2, int b) :m_a1(a1),m_a2(a2) {
cout << "B(int,int,int)..." << endl;
m_b = b;
}

void printB() {
cout << "b = " << m_b << endl;
m_a1.printA();
m_a2.printA();
}

~B() {
cout << "~B()..." << endl;
}
private:
int m_b;
A m_a1;
A m_a2;
};

void test1() {
A a1(10), a2(100);
B b(a1, a2, 1000);
b.printB();
}

int main() {
B b(10, 20, 300);
b.printB();
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>

using namespace std;

class A {
public:
A(int a) {
cout << "A()..." << endl;
m_a = a;
}

~A() {
cout << "~A()" << endl;
}

void printA() {
cout << "a = " << m_a << endl;
}

private:
int m_a;
};

// 构造函数的初始化列表
class B {
public:
B(A&a1, A&a2, int b) :m_a1(a1),m_a2(a2){
cout << "B(A&,A&,int)..." << endl;
m_b = b;
}

void printB() {
cout << "b = " << m_b << endl;
m_a1.printA();
m_a2.printA();
}

~B() {
cout << "~B()" << endl;
}
private:
int m_b;
A m_a1;
A m_a2;
};

int main() {
A a1(10), a2(100);
B b(a1, a2, 1000);
b.printB();
return 0;
}

当A的对象是B的一个成员的时候,在初始化对象的时候,无法给B分配空间,因为无法初始化A类对象

初始化列表中的初始化顺序,与声明顺序有关,与前后赋值顺序无关

当类成员中含有一个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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <iostream>

using namespace std;

class ABCD {
public:
ABCD(int a, int b, int c) {
_a = a;
_b = b;
_c = c;
printf("ABCD() construct,a:%d,b:%d,c:%d\n", _a, _b, _c);
}
~ABCD() {
printf("~ABCD() construct,a:%d,b:%d,c:%d\n", _a, _b, _c);

}
int getA() {
return _a;
}
private:
int _a;
int _b;
int _c;
};

class MyE {
public:
MyE() :abcd1(1, 2, 3), abcd2(4, 5, 6), m(100) {
cout << "MyD()" << endl;
}
~MyE() {
cout << "~MyD()" << endl;
}
MyE(const MyE& obj) :abcd1(7, 8, 9), abcd2(10, 11, 12), m(100) {
printf("MyD(const MyD&obj)\n");
}
public:
ABCD abcd1;
ABCD abcd2;
const int m;
};

int doThing(MyE mye1) {//mye1
printf("doThing() mye1.abcd1.a:%d\n", mye1.abcd1.getA());
return 0;
}

int run() {
MyE myE;
doThing(myE);
return 0;
}

int run2() {
printf("run2 start...\n");
ABCD(400, 500, 600);//临时对象的生命周期
//ABCD abcd = ABCD(100,200,300);
printf("run2 end\n");
return 0;
}

int main() {
run();
return 0;
}

7.5 new和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
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
#include <iostream>

using namespace std;

class Test {
public:
Test() {
cout << "Test()..." << endl;
m_a = 0;
m_b = 0;
}
Test(int a, int b) {
cout << "Test(int,int)" << endl;
m_a = a;
m_b = b;
}
void prinT() {
cout << "prinT:" << m_a << "," << m_b << endl;
}
~Test() {
cout << "~Test(int,int)" << endl;
}
private:
int m_a;
int m_b;
};

// C语言中
void test1() {
int* p = (int*)malloc(sizeof(int));
*p = 10;
if (p != NULL) {
free(p);
p = NULL;
}

int* array_p = (int*)malloc(sizeof(int) * 10);
for (int i = 0; i < 10; i++) {
array_p[i] = i + 1;
}
for (int i = 0; i < 10; i++) {
printf("%d", array_p[i]);
}
printf("\n");
if (array_p != NULL) {
free(array_p);
array_p = NULL;
}
cout << "=================" << endl;
Test* tp = (Test*)malloc(sizeof(Test));
tp->prinT();
if (tp != NULL) {
free(tp);
tp = NULL;
}
}

// C++中
void test2() {
int* p = new int;
*p = 10;
if (p != NULL) {
delete p;
p = NULL;
}
// int a(10);等价于a=10
int* array_p = new int[10];
for (int i = 0; i < 10; i++) {
array_p[i] = i + 1;
}
for (int i = 0; i < 10; i++) {
cout << array_p[i];
}
cout << endl;
if (array_p != NULL) {
delete[]array_p;
}
cout << "=================" << endl;
Test* tp = new Test(10, 20);// 触发有参构造
tp->prinT();
// Test* tp2 = new Test;// 触发无参构造
// tp2->prinT();
if (tp != NULL) {
delete tp;
tp = NULL;
}
}

int main() {
test1();
cout << "-----------" << endl;
test2();
return 0;
}
// C语言输出的m_a,m_b为乱码

malloc,free是函数,标准库(stdlib.h)。new在堆上初始化一个对象的时候,会触发对象的构造函数,malloc不能;delete触发析构函数而free则不

7.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
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 AA {
public:
AA(int a, int b) {
m_a = a;
m_b = b;
}

int getC() {
m_c++;
return m_c;
}

// 静态的成员方法
static int& getCC() {
return m_c;
}
private:
// static修饰的静态成员变量
static int m_c;
int m_a;
int m_b;
};

// 静态成员变量的初始化,一定要在类的外边
int AA::m_c = 0;

int main() {
AA a1(10, 20);
AA a2(100, 200);
cout << a1.getC() << endl;
cout << a2.getC() << endl;
#if 0
当m_c为public成员变量时
AA::m_c = 200;
// a1.m_c = 200相同作用
// 共用静态区
// 访问空间中的静态区
#endif
a1.getCC() = 200;
//AA::getCC() = 200相同作用
cout << a1.getC() << endl;
cout << a2.getC() << endl;
return 0;
}

7.6.1 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
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>

using namespace std;

class Box {
public:
Box(int l, int w) {
len = l;
width = w;
}

int volume() {
int v = len * width * hight;
cout << "高度是" << hight << endl;
cout << "体积是" << v<< endl;
return v;
}

static void changeHight(int h) {
hight = h;
}
private:
int len;
int width;
static int hight;
};

int Box::hight = 100;

int main() {
Box b1(10, 20);
Box b2(100, 200);
b1.volume();
b2.volume();
Box::changeHight(300);
b1.volume();
b2.volume();
return 0;
}

7.6.2 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
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
#include <iostream>

using namespace std;

class C1 {
public:
int i;// 4
int j;// 4
int k;// 4
};//12

class C2 {
public:
int i;// 4
int j;// 4
int k;// 4
static int m;
public:
int getK()const {
return k;
}
void getK(int val) {
k = val;
}
};//12

struct S1 {
int i;
int j;
int k;
};

struct S2 {
int i;
int j;
int k;
static int m;
};

int main() {
cout << "c1:" << sizeof(C1) << endl;
cout << "c1:" << sizeof(C2) << endl;
C2 c1, c2;
c1.getK();// 返回c1的k
c2.getK();// 返回c2的k
cout << "------------------" << endl;
cout << "c1:" << sizeof(S1) << endl;
cout << "c1:" << sizeof(S2) << endl;
return 0;
}
// 只有普通成员变量才会占对象空间

7.6.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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include <iostream>

using namespace std;

class Goods {
public:
Goods() {
weight = 0;
next = NULL;
cout << "创建了一个重量为" << weight << "的货物" << endl;
}

Goods(int w) {
//需要创建一个w的货物,并且仓库加上这个重量
weight = w;
next = NULL;
total_weight += w;
cout << "创建了一个重量为" << weight << "的货物" << endl;
}

~Goods() {
//仓库减少这个货物的重量
cout << "删除了一箱重量是" << weight << "的货物" << endl;
total_weight -= weight;
}

static int get_total_weight() {
return total_weight;
}

Goods* next;
private:
int weight;
static int total_weight;//仓库总重量
};

int Goods::total_weight = 0;

void buy(Goods* &head,int w) {
//用二级指针或一级指针引用来改变
//创建一个货物 重量是w
Goods* new_goods = new Goods(w);
if (head == NULL) {
head = new_goods;
}
else {
new_goods->next = head;
head = new_goods;
}
}

void sale(Goods*& head) {
if (head == NULL) {
cout << "仓库中已经没有货物了。。" << endl;
return;
}
Goods* temp = head;
head = head->next;
delete temp;
cout << "saled." << endl;
}

int main() {
int choice = 0;
Goods* head = NULL;
int w;
do {
cout << "1 进货" << endl;
cout << "2 出货" << endl;
cout << "0 退出" << endl;
cin >> choice;
switch (choice) {
case 1:
//进货
cout << "请输入要创建货物的重量" << endl;
cin >> w;
buy(head, w);
break;
case 2:
//出货
sale(head);
break;
case 0:
//退出
return 0;
default:
break;
}
cout << "当前仓库的总重量是" << Goods::get_total_weight() << endl;
} while (1);
return 0;
}

7.7 this指针

7.7.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 Test {
public:
Test(int i) {
mI = i;
}

int getI(Test* this) {
//this就是指向调用该成员函数方法的对象地址
return this->mI;
//return mI;
}
private:
int mI;
};

#if 0
struct Test {
int mI;
};

void Test_init(Test* pthis, int i) {
pthis->mI = i;
}

int getI(struct Test* pthis) {
return pthis->mI;
}
#endif

int main() {
Test t1(10);//Test(&t1,10)
Test t2(20);
t1.getI();//getI(&t1)
return 0;
}

7.7.2 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
#include <iostream>

using namespace std;

class Test {
public:
Test(int k) {
this->m_k = k;
}

int getK()const {// 成员函数尾部出现const,修饰this指针
// 此时类型为const Test const*
// this->m_k = 100;(√)
// this指针不是const Test* int型
// this++;(×)
// this指针是一个常指针,Test const*
return this->m_k;
}
private:
int m_k;
};

int main() {
Test t1(10);// Test(&t1,10)
Test t2(20);// Test(&t1,20)
return 0;
}

7.8 全局函数和成员函数

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
#include <iostream>

using namespace std;

class Test {
public:
Test(int a, int b) {
this->a = a;
this->b = b;
}

void prinT() {
cout << "a = " << this->a << ",b = " << this->b << endl;
}

int getA() {
return this->a;
}

int getB() {
return this->b;
}
// 成员方法
Test TestAdd(Test& another) {
Test temp(this->a + another.a, this->b + another.b);
return temp;
}
// +=方法
Test& TestAdd2(Test& another) {
this->a += another.a;
this->b += another.b;
return* this;
// 如果想返回一个对象本身,在成员方法中,用*this返回
}
private:
int a;
int b;
};

#if 0
// 1 在全局提供一个两个Test相加的函数
Test TestAdd(Test& t1, Test& t2) {
Test temp(t1.getA() + t2.getA(), t1.getB() + t2.getB());
return temp;
}
#endif

int main() {
Test t1(10, 20);
Test t2(100, 200);
// Test t3 = TestAdd(t1, t2);
Test t3 = t1.TestAdd(t2);
t3.prinT();
// ((t1+=t2)+=t2)+=t2
// 如果想对一个对象连续调用成员方法,每次都会改变对象本身,成员方法需要返回引用
t1.TestAdd2(t2).TestAdd2(t2);
t1.prinT();
return 0;
}
// 返回对象本身

7.9 自定义的数组类

代码如下:
MyArray.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#pragma once
class MyArray
{
public:
MyArray();
MyArray(int len);
MyArray(const MyArray& another);
~MyArray();
void setData(int index, int data);
int getData(int index);
int getLen();
private:
int len;
int* space;
};

MyArray.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
#include "MyArray.h"

MyArray::MyArray() {
cout << "MyArray()..." << endl;
this->len = 0;
this->space = NULL;
}

MyArray::MyArray(int len) {
if (len <= 0) {
this->len = 0;
return;
}
else {
this->len = len;
//给space开辟空间
this->space = new int[this->len];
cout << "MyArray(int len)..." << endl;
}
}

void MyArray::operator=(const MyArray& another) {
if (another.len >= 0) {
this->len + another.len;
//深拷贝
this->space = new int[this->len];
for (int i = 0; i < this->len; i++) {
this->space[i] = another.space[i];
}
cout << "MyArray::MyArray(const MyArray& another)..." << endl;
}
}

~MyArray::MyArray() {
if (this->space != NULL) {
delete[]this->space;
this->space = NULL;
len = 0;
cout << "MyArray::~MyArray()..." << endl;
}
}

void MyArray::setData(int index, int data) {
if (this->space != NULL) {
this->space[index] = data;
}
}

int MyArray::getData(int index) {
return this->space[index];
}

int MyArray::getLen() {
return this->len;
}

main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include "MyArray.h"

using namespace std;

int main() {
MyArray array1(10);// 开辟10元素的数组
// 赋值操作
for (int i = 0; i < 10; i++) {
array1.setData(i, i + 10);
}
cout << "----------------" << endl;
for (int i = 0; i < 10; i++) {
cout << array1.getData(i) << " ";
}
cout << endl;
MyArray array2 = array1;
/*MyArray array3;
array3 = array1;*/
return 0;
}

7.10 友元

7.10.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
#include<iostream>
#include<cmath>

using namespace std;

class Point;

//友元类
class PointManager {
public:
double PointDistance(Point& p1, Point& p2);
};

class Point {
public:
//声明全局函数PointDistance是我类Point类的一个友元函数
//friend double PointDistance(Point& p1, Point& p2);
friend double PointManager::PointDistance(Point& p1, Point& p2);
Point(int x, int y) {
this->x = x;
this->y = y;
}

int getX() {
return this->x;
}

int getY() {
return this->y;
}

private:
int x;
int y;
};

#if 0
//友元函数
double PointDistance(Point& p1, Point& p2) {
double dis;
int dd_x = p1.x - p2.x;
int dd_y = p1.y - p2.y;
dis = sqrt(dd_x * dd_x + dd_y * dd_y);
return dis;
}
#endif

double PointManager::PointDistance(Point& p1, Point& p2) {
double dis;
int dd_x = p1.x - p2.x;
int dd_y = p1.y - p2.y;
dis = sqrt(dd_x * dd_x + dd_y * dd_y);
return dis;
}

int main(){
Point p1(1, 2);
Point p2(2, 2);
//cout << PointDistance(p1, p2) << endl;
PointManager pm;
cout << pm.PointDistance(p1, p2) << endl;
return 0;
}

友元函数提高了程序的运行效率(减少了类型检查和安全性检查(需要时间开销),破坏了类的封装性和隐藏性,使得非成员函数可以访问类的私有成员

7.10.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
#include <iostream>

using namespace std;

class A {
public:
A(int a) {
this->a = a;
}

void printA() {
cout << "a = " << this->a << endl;
}
//声明一个友元类B
friend class B;
private:
int a;
};

class B {
public:
B(int b) {
this -> b = b;
}

void printB() {
A objA(100);
cout << objA.a << endl;
cout << "b = " << this->b << endl;
}
private:
int b;
};

int main() {
B bObj(200);
bObj.printB();
return 0;
}

友元关系不能被继承。友元关系是单向的,不具有交换性。友元关系不具有传递性

8 操作符重载

8.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
#include <iostream>

using namespace std;

class Complex {
public:
friend Complex complexAdd(Complex& c1, Complex& c2);
//friend Complex operator + (Complex& c1, Complex& c2);
Complex(int a, int b) {
this->a = a;
this->b = b;
}

void printComplex() {
cout << "(" << this->a << "," << this->b << "i)" << endl;
}
Complex complexAdd(Complex& another) {
Complex temp(this->a + another.a, this->b + another.b);
return temp;
}

Complex operator+(Complex& another) {
Complex temp(this->a + another.a, this->b + another.b);
return temp;
}
private:
int a;//实数
int b;//虚数
};

Complex complexAdd(Complex& c1, Complex& c2) {
Complex temp(c1.a + c2.a, c1.b + c2.b);
return temp;
}
//操作符重载写在全局
#if 0
Complex operator + (Complex & c1, Complex & c2) {
Complex temp(c1.a + c2.a, c1.b + c2.b);
return temp;
}
#endif

int main() {
Complex c1(1, 2);
Complex c2(2, 4);
c1.printComplex();
c2.printComplex();
//Complex c3 = complexAdd(c1, c2);
//Complex c3 = c1.complexAdd(c2);
//Complex c3 = c1 + c2;
//Complex c3 = operator+(c1, c2);
Complex c3 = c1.operator+(c2);
c3.printComplex();
return 0;
}

8.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 Complex {
public:
Complex(int a,int b) {
this->a = a;
this->b = b;
}

void printComplex() {
cout << "(" << this->a << "," << this->b << "i)" << endl;
}

//friend Complex& operator+=(Complex& c1,Complex& c2);
friend Complex& operator-=(Complex& c1, Complex& c2);

Complex& operator+=(Complex& another) {
this->a += another.a;
this->b += another.b;
return *this;
}
private:
int a;//实数
int b;//虚数
};

//全局
#if 0
Complex& operator+=(Complex& c1, Complex& c2) {
c1.a -= c2.a;
c1.b -= c2.b;
return c1;
}
#endif

int main() {
Complex c1(1, 2);
Complex c2(2, 4);
(c1 += c2) += c2;//c1.operator+=(c2).operator(c2)
c1.printComplex();
c2.printComplex();
c1 -= c2;
c1.printComplex();
return 0;
}

8.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
#include<iostream>

using namespace std;

class Complex {
public:
Complex(int a, int b) {
this->a = a;
this->b = b;
}

void printComplex() {
cout << "(" << this->a << ", " << this->b << "i)" << endl;
}

//friend Complex& operator++(Complex& c);
//friend const Complex operator++(Complex&c1,int);

Complex& operator++() {
this->a++;
this->b++;
return *this;
}

const Complex operator++(int) {
//亚元:区分两个函数
Complex temp(this->a, this->b);
this->a++;
this->b++;
return temp;
}
private:
int a;
int b;
};

#if 0
//重载的是前++运算符
Complex& operator++(Complex& c) {
c.a++;
c.b++;
return c;
}
#endif

#if 0
//重载的是后++运算符
//用const修饰表示不能连加,值不能改变
//用占位参数来表示前++和后++的区别
const Complex operator++(Complex& c1, int) {
Complex temp(c1.a, c1.b);
c1.a++;
c1.b++;
return temp;
}
#endif
int main() {
Complex c1(1, 2);
//++++c1;
c1++;
//后++普通情况不能累加
c1.printComplex();
//++++c1;
return 0;
}

8.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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>

using namespace std;

class Complex {
public:
Complex(int a, int b) {
this->a = a;
this->b = b;
}

void printComplex() {
cout << "(" << this->a << ", " << this->b << "i)" << endl;
}

friend ostream& operator<<(ostream& os, Complex& c);
friend istream& operator>>(istream& is, Complex& c);
//<<操作符只能写在全局,不能够写在成员方法中,否则调用的顺序会变反 c1<<cout;
#if 0
ostream& operator<<(ostream& os)//c1.operator<<(cout){
os << "(" << this->a << "," << this->b << "i)" << endl;
return os;
#endif
private:
int a;//实数
int b;//虚数
};

#if 1
ostream& operator<<(ostream& os, Complex& c) {
os << "(" << c.a << "," << c.b << ",)" << endl;
return os;
}

istream& operator>>(istream& is, Complex& c) {
cout << "a:";
is >> c.a;
cout << "b:";
is >> c.b;
return is;
}
#endif

int main() {
Complex c1(1, 2);
cin >> c1;//operator>>(cin,c1)
cout << c1;
//c1<<cout;
//cout.operator<<(c1);
//cout << c1 << " " << c1 << endl;
return 0;
}

8.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
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
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>

using namespace std;

class Student {
public:
Student() {
this->id = 0;
this->name = NULL;
}
Student(int id, const char* name) {
this->id = id;
//this->name = name;
int len = strlen(name);
this->name = new char[len + 1];
strcpy(this->name, name);
}

Student(const Student& another) {
this->id = another.id;
//深拷贝
int len = strlen(another.name);
this->name = new char[len + 1];
strcpy(this->name, another.name);
}

Student& operator=(const Student& another) {
//1 防止自身赋值
if (this == &another) {
return* this;
}

//2 先将自身的额外开辟的空间回收掉
if (this->name != NULL) {
delete[] this->name;
this->name = NULL;
this->id = 0;
}

//3 执行深拷贝
this->id = another.id;
int len = strlen(another.name);
this->name = new char[len + 1];
strcpy(this->name, another.name);

//4 返回本身
return* this;
}

void printS() {
cout << name << endl;
}

~Student() {
if (this->name != NULL) {
delete[] this->name;
this->name = NULL;
this->id = 0;
}
}
private:
int id;
char* name;
};

int main() {
Student s1(1, "zhang3");
Student s2(s1);//拷贝构造
s2 = s1;
Student s3(2, "li4");
//s2 = s3 = s1;//s2 = 赋值操作符
s1.printS();
s2.printS();
s3.printS();
return 0;
}

8.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
28
29
30
31
32
33
34
35
36
#include <iostream>

using namespace std;

class Sqr {
public:
Sqr(int a) {
this->a = a;
}

int operator()(int value) {
return value * value;
}

int operator()(int value1, int value2) {
return value1 * value2;
}
private:
int a;
};

void func(int a) {

}

int main() {
Sqr s(10);
int value = s(2);
//s.operator()(2);
//将一个对象 当成一个普通函数来调用。
//称这种对象是仿函数,伪函数,函数对象
cout << value << endl;
value = s(10, 20);
cout << value << endl;
return 0;
}

8.7 重载new和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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <iostream>

using namespace std;

class A {
public:
A() {
cout << "A()..." << endl;
}
A(int a) {
cout << "A(int)..." << endl;
this->a = a;
}

//重载的new操作符 依然会触发对象
void* operator new(size_t size) {
cout << "重载了new操作符" << endl;
return malloc(size);
}

void* operator new[](size_t size) {
cout << "重载了new[]操作符" << endl;
return malloc(size);
}

void operator delete(void* p) {
cout << "重载了delete操作符" << endl;
if (p != NULL) {
free(p);
p = NULL;
}
}

void operator delete[](void* p) {
cout << "重载了delete[]操作符" << endl;
if (p != NULL) {
free(p);
p = NULL;
}
}

~A() {
cout << "~A()..." << endl;
}
private:
int a;
};

int main() {
//char* array = malloc(sizeof(char) * 80);
//int* value_p = new int;
A* array_p = new A[10];
//array_p->operator new[](sizeof(A[10]));
delete[]array_p;
A* ap = new A(10);
//ap->operator new(sizeof(A));
delete ap;
return 0;
}

8.8 不建议重载&,|操作符

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
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>

using namespace std;

class Test {
public:
Test(int value) {
this->value = value;
}

Test operator+(Test &another) {
cout << "执行了+操作符重载" << endl;
Test temp(this->value + another.value);
return temp;
}

bool operator&&(Test another) {
cout << "执行了&&操作符重载" << endl;
if (this->value && another.value) {
return true;
}
else {
return false;
}
}

bool operator||(Test another) {
cout << "重载了||操作符" << endl;
if (this->value || another.value) {
return true;
}
else {
return false;
}
}

~Test() {
cout << "~Test()..." << endl;
}
private:
int value;
};

int main() {
int a = 1;
int b = 20;
Test t1(0);
Test t2(20);
//重载&&,并不会发生短路现象
if (t1 && (t1 + t2)) {//t1.operator&&(t1.operator+(t2))
cout << "为真" << endl;
}
else {
cout << "为假" << endl;
}
cout << "---------------" << endl;
if (t1 || (t1 + t2)) {
cout << "为真" << endl;
}
else {
cout << "为假" << endl;
}
return 0;
}

8.9 自定义智能指针

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
#define _CRT_SECUER_NO_WARNING
#include <iostream>
#include <memory>

using namespace std;

class A {
public:
A(int a) {
cout << "A()..." << endl;
this->a = a;
}

void func() {
cout << "a = " << this -> a << endl;
}

~A() {
cout << "~A()..." << endl;
}
private:
int a;
};

class MyAutoPtr {
public:
MyAutoPtr(void* ptr) {
this->ptr = ptr;//ptr=new A(10)
}
~MyAutoPtr() {
cout << "~MyAutoPtr()..." << endl;
if (this->ptr != NULL) {
delete ptr;
this->ptr = NULL;
}
}
A* operator->() {
return this->ptr;
}

A& operator*() {
return *ptr;
}
private:
A* ptr;
};

void test1() {
#if 0
A* ap = new A(10);
ap->func();
(*ap).func();
delete ap;
#endif
auto_ptr<A> ptr(new A(10));
ptr->func();
(*ptr).func();
}

void test2() {
MyAutoPtr my_p(new A(10));
my_p->func();//my_p.ptr->func()
(*my_p).func();//*ptr.func
//重载*
}

int main() {
//test1();
test2();
return 0;
}

8.10 自定义字符串类

MyString.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
#include "MyString.h"


MyString::MyString()
{
this->len = 0;
this->str =NULL;
}

MyString::MyString(const char *str)
{
if (str == NULL) {
this->len = 0;
this->str = new char[0 + 1];
strcpy(this->str, "");
}
else {
int len = strlen(str);
this->len = len;

this->str = new char[len + 1];
strcpy(this->str, str);
}
}

//初始化时候被调用的
MyString::MyString(const MyString &another)
{
this->len = another.len;
this->str = new char[this->len + 1];
strcpy(this->str, another.str);
}



MyString::~MyString()
{
if (this->str != NULL) {
cout << this->str << "执行了析构函数" << endl;
delete this->str;
this->str = NULL;
this->len = 0;
}
}

char & MyString::operator[](int index)
{
return this->str[index];
}

MyString & MyString::operator=(const MyString &another)
{
if (this == &another) {
return *this;
}

if (this->str != NULL) {
delete[] this->str;
this->str = NULL;
this->len = 0;
}

this->len = another.len;
this->str = new char[this->len + 1];
strcpy(this->str, another.str);

return *this;
}

ostream & operator<<(ostream &os, MyString&s)
{
os << s.str;
return os;
}

istream & operator>>(istream &is, MyString &s)
{
//1 将s之前的字符串释放掉
if (s.str != NULL) {
delete[] s.str;
s.str = NULL;
s.len = 0;
}

//2 通过cin添加新的字符串
char temp_str[4096] = { 0 };
cin >> temp_str;

int len = strlen(temp_str);
s.str = new char[len + 1];
strcpy(s.str, temp_str);
s.len = len;

return is;
}

MyString MyString::operator+(MyString &another)
{
MyString temp;

int len = this->len + another.len;

temp.len = len;

temp.str = new char[len + 1];
memset(temp.str, 0, len + 1);
strcat(temp.str, this->str);
strcat(temp.str, another.str);

return temp;
}

MyString.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
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;

class MyString
{
public:
MyString();
//MyString(int len); //创建一个长度是len的string对象
MyString(const char *str);
MyString(const MyString &another);
~MyString();
//重载操作符[]
char &operator[](int index);
//重载操作符>>
friend istream & operator>>(istream &is, MyString &s);
//重载=操作符
MyString & operator=(const MyString &another);
//重载==操作符
//重载!=操作符
//重载+操作符
MyString operator+(MyString &another);
//重载操作符<<
friend ostream & operator<<(ostream &os, MyString&s);
private:
int len;
char *str;
};

自定义的字符串类

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
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include "MyString.h"

using namespace std;

int main(void)
{
string s1;
MyString s1("abc");
MyString s2("123");
//cout << s1 + s2 << endl;
cout << s1 << endl;
cout << s2 << endl;
#if 0
MyString s1("abc");
MyString s2(s1);
MyString s3 = "123";
cout << s1 << endl;
cout << s2 << endl;
s1[1] = 'x';
cout << s1 << endl;
s1 = s3;
cout << s1 << endl;
#endif
return 0;
}

9 继承

9.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
#define _CRT_SECUE_NO_WARNING
#include <iostream>

using namespace std;

class A {
public:
void func() {
cout << "funcA" << endl;
}
int a;
};

//类B拥有类A的成员变量,B has A,//类B 依赖于类A
class B {
public:
void funcB() {

}
A a;
};
//耦合度 高内聚 低耦合

//类C的成员方法 需要类A的形参,C use A,//类C依赖于类A
class C {
public:
void funC(A* a) {

}
void funC2() {

}
};

//D继承于A 类D如果是继承类A 类D is A.//类D继承于A耦合度很高
class D :public A {
public:
void funcD() {
cout << this->a << endl;
}
};

class E :public D {

};

int main() {

return 0;
}

9.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
#define _CRT_SECUE_NO_WARNING
#include <iostream>
#include <string>

using namespace std;

class Student {
public:
Student() {

}

Student(int id, string name) {
this->id = id;
this->name = name;
}

void printS() {
cout << "id = " << this->id << ", name = " << this->name << endl;
}
int id;
string name;
};

//创建一个新的学生表,增加score功能
class Student2 {
public:
Student2(int id, string name, int score) {
this->id = id;
this->name = name;
this->score = score;
}

void printS() {
cout << "id = " << this->id << ", name = " << this->name << endl;
cout << "score = " << this->score << endl;
}
private:
int id;
string name;
//add
int score;
};

//通过继承创建一个新的学生类
class Student3 :public Student {
public:
Student3(int id, string name, int score) :Student(id, name) {
this->score = score;
}

void printS() {
Student::printS();
cout << "score = " << this->score << endl;
}
private:
int score;
};

int main() {
Student3 s3(1, "zhang3", 80);
s3.printS();
return 0;
}

9.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
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
#define CRT_SECUE_NO_WARNING
#include <iostream>
#include <memory>

using namespace std;

//1.只要是父类中的private成员,不管是什么继承方式,儿子都访问不了
//2.如果是public继承,儿子中的访问控制权限保持不变
//3.如果是保护继承,儿子中父亲除了private成员,其余在儿子中都是protected
//4.如果是私有继承,儿子中父亲的除了private成员,其余在儿子中都是private成员

class Parent {
public:
int pub;//在类的内部和外部都能访问
protected:
int pro;//在类的内部都可以访问,在类的外部不可以访问
private:
int pri;//在类的内部可以访问,在类的外部不可以访问
};

//公有继承
class Child :public Parent {
public:
void func()
{
cout << pub << endl; //pub父类的public成员变量,在public继承类的内部,外部都可以访问
cout << pro << endl;//pro 是父类protected成员变量 在public继承类的内部可以访问。外部访问不了
//此时的pro在孙子能够访问,说此时pro不是private成员,而是protected成员
//cout << pri << endl; //pri 是父类private成员变量 在public继承类的内部,外部不可以访问
}
};

//孙子类
class SubChild : public Child
{
void sub_func()
{
cout << pro << endl;
}
};

//保护继承
class Child2 :protected Parent
{
public:
void func2() {
pub;//此时pub通过protected继承 能够在类的内部访问。
//pub 在类的内部可以访问, 类的外部访问不了, 类的儿子可以访问
//pub 就是protected成员
pro;//pro和pub 是一样的性质,pro也是protected成员
//pri;
}
};

class Sub_child2 :public Child2
{
public:
void sub_func2() {
pub;
pro;
}
};

//私有继承
class Child3 :private Parent
{
public:
void func3()
{
pub;//pub 在类的内部可以访问。在类的内部可以访问,类的外部不能访问。
//pub 在儿子中访问不了,说明pub在Child3中是 私有成员
pro;//pro 根pub的性质是一样, 也是私有成员。
//pri;
}
};

class Sub_Child3 :public Child3
{
public:
void sub_fun3()
{
//pub;
//pro;
//都访问不了
}
};

//三看原则:
//1 看调用的成员变量是在类的内部还是类的外部
//2 看儿子继承方式,
//3 当前变量在儿子中的变量在父亲中的访问控制权限

int main() {
Child c1;
c1.func();
c1.pub;
//c1.pri;
//Child2 c2;
//c2.pub;
//c2.pro;
Child3 c3;
//c3.pub;
//c3.pro;
Child2 c2;
//c2.pub;
//c2.pro;
c1.pub;
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
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
#include <iostream>

using namespace std;

class A {
private:
int a;
protected:
int b;
public:
int c;
A() {
a = 0;
b = 0;
c = 0;
}

void set(int a, int b, int c)
{
this->a = a;
this->b = b;
this->c = c;
}
};

class B :public A {
public:
void print() {
//cout << "a = " << a; //a是父类的私有成员访问不了
cout << "b = " << b; //b此时是保护成员,类的内部可以访问
cout << "c = " << c << endl; //c此时是公有成员,类的内部可以访问
}
};

class C : protected A {
public:
void print()
{
//cout << "a = " << a; //a是父类的私有成员访问不了
cout << "b = " << b; //b 在子类中是protected权限,类的内部可以访问。
cout << "c = " << c << endl; //c 子类的protected成员,类的内部可以访问。
}
};

class D :private A{
public:
void print()
{
//cout << "a = " << a; //a是父类的私有成员访问不了
cout << "b = " << b << endl; //b 此时是private成员,类的内部可以访问。
cout << "c = " << c << endl; //c 此时是private成员,类的内部可以访问。
}
};

int main() {
A aa;
B bb;
C cc;
D dd;
aa.c = 100; //c 是公有,类的外部可以访问。
bb.c = 100; //Bpublic 继承与A,保持权限不变,c 是公有,类的外部可以访问
//cc.c = 100; //C protected 继承与A,c 在此类中是protected成员,类的外部不能访问。
//dd.c = 100; //D private 继承与A,c在此类中private成员,类的外部不能访问。
aa.set(1, 2, 3); //能访问
bb.set(10, 20, 30); //能访问
//cc.set(40, 50, 60);//不能访问
//dd.set(70, 80, 90);//不能访问
bb.print(); //print 是定义在B类 public成员函数,在类的外部可以访问。
cc.print(); //print 是定义在C类 public成员函数,在类的外部可以访问。
dd.print(); //print 是定义在D类 public成员函数,在类的外部可以访问。
return 0;
}

9.4 继承中的构造和析构

9.4.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
#define _CRT_SECUE_NO_WARNING
#include <iostream>

using namespace std;

/*
子类对象可以当作父类对象使用。
子类对象可以直接赋值给父类对象。
子类对象可以直接初始化父类对象.
***父类指针可以直接指向子类对象***
父类引用可以直接引用子类对象
*/

class Parent
{
public:
void printP() {
cout << "a " << this->a << endl;
}
int a;
};

class Child :public Parent
{
public:
void printC()
{
cout << "b = " << this->b << endl;
}
int b;
};

void myPrint(Parent* pp)
{
pp->printP();
}

int main() {
//Parent p;
//Child c = p; //p对象填充不满c对象空间,
//Child c;
//Parent p = c;//c 对象所占用的内存空间 >= p对象占用空间 能够填充满p对象所需要空间。
//p = c;
//c.printP(); //c 能够当做父类 p 来使用。
Parent* pp = NULL;//父类指针
Child* cp = NULL;//子类指针
Parent p;//父类对象
Child c; //子类对象
pp = &c;//c 内存布局能够满足父类指针的全部需求, 可以用一个儿子的对象地址给父类指针赋值。
myPrint(&p);
myPrint(&c);
return 0;
}

9.4.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
#define _CRT_SECUE_NO_WARNING
#include <iostream>

using namespace std;

class Parent
{
public:
Parent()
{
cout << "Parent().." << endl;
a = 0;
}
Parent(int a) {
cout << "Parent(int)..." << endl;
this->a = a;
}
~Parent() {
cout << "~Parent" << endl;
}
int a;
};

class Child :public Parent
{
public:
//在调用子类的构造函数时候,一定会调用父类的构造函数
//父类先构造,子类后构造
Child(int a, int b) :Parent(a)
{
cout << "Child(int, int)..." << endl;
this->b = b;
}

void printC() {
cout << "b = " << b << endl;
}

~Child() {
cout << "~Child()..." << endl;
}
int b;
};

int main() {
Child c(10, 20);
c.printC();
return 0;
}

9.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
26
27
28
29
30
31
32
33
34
35
36
#define _CRT_SECUE_NO_WARNING
#include <iostream>

using namespace std;

class Parent
{
public:
Parent(int a) {
this->a = a;
}

int a;
};

class Child :public Parent
{
public:
Child(int p_a, int c_a) :Parent(p_a)
{
this->a = c_a;
}

void print()
{
cout << Parent::a << endl;
cout << this->a << endl;//child's a
}
int a;
};

int main() {
Child c(10, 100);
c.print();
return 0;
}

9.6 继承中的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
27
28
29
30
31
32
33
34
35
36
37
38
39
#define _CRT_SECUE_NO_WARNING
#include <iostream>

using namespace std;

class A
{
public:
static int a;
private:

};

class B :public A
{
public:
private:
};

int A::a = 100;//静态成员变量 初始化

int main() {
A a1;
A a2;
cout << a1.a << endl;
cout << a2.a << endl;
A::a = 300;
cout << a1.a << endl;
cout << a2.a << endl;
B b1;
B b2;
A::a = 400;
cout << "------" << endl;
cout << b1.a << endl;
cout << b2.a << endl;
cout << a1.a << endl;
cout << a2.a << endl;
return 0;
}

9.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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#define _CRT_SECUE_NO_WARNING
#include <iostream>

using namespace std;

//家具类
class Furniture
{
public:
int m; //材质
};

//将父亲类继承爷爷类,改成虚继承,防止儿子在多继承我的时候,出现爷爷中的变量会拷贝多份
class Bed :virtual public Furniture
{
public:
void sleep() {
cout << "在床上睡觉" << endl;
}
};

class Sofa :virtual public Furniture
{
public:
void sit() {
cout << "在沙发上休息" << endl;
}
};

//沙发床
class SofaBed :public Bed, public Sofa
{
public:
void SleepAndSit() {
sleep();
sit();
}
};

int main() {
Bed b;
b.sleep();
Sofa s;
s.sit();
cout << " ------ " << endl;
SofaBed sb;
sb.SleepAndSit();
sb.m = 100;//此时只有一个m
//sb.Bed::m = 100;
//sb.Sofa::m = 200;
return 0;
}

10 多态

10.1 什么是多态

10.1.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
#define _CRT_SECUE_NO_WARNING
#include <iostream>
#include <string>

using namespace std;

//岳不群
class Yuebuqun
{
public:
Yuebuqun(string kongfu)
{
this->kongfu = kongfu;
}

virtual void fight() //标识修饰一个成员方法是一个虚函数。
{
cout << "岳不群" << "使出了" << kongfu << "打人" << endl;
}

void print()
{

}

string kongfu;
};

//林平之继承了岳不群
class Linpingzhi :public Yuebuqun
{
public:
Linpingzhi(string kongfu) :Yuebuqun(kongfu)
{

}

//如果说父类中有一个虚函数是fight(),子类如果去重写这个虚函数
void fight()
{
cout << "林平之" << "使出了" << kongfu << "打人" << endl;
}

void print()
{

}
};

class Linghuchong :public Yuebuqun
{
public:
Linghuchong(string kongfu) :Yuebuqun(kongfu)
{

}

void fight()
{
cout << "令狐冲 " << "使用了" << kongfu << endl;
}
};

//在全局提供一个打斗的方法
void fightPeople(Yuebuqun* hero)//Yuebuqun *hero = xiaopp; Yuebuqun *hero = xiaoyy;
{
cout << "调用打人的方法" << endl;
hero->fight();//希望传递进来的如果是子类,调用子类的fight
//如果传递进来的是父类, 调用父类的fight
//这种行为就是 多态行为。
}

//多态发生的三个必要条件:
//1. 要有继承。
//2. 要有虚函数重写。
//3. 父类指针或引用指向子类对象。

int main() {
Yuebuqun* xiaoyy = new Yuebuqun("葵花宝典");
//xiaoyy->fight();
Linpingzhi* xiaopp = new Linpingzhi("辟邪剑谱");
//xiaopp->fight();
Linghuchong* xiaoll = new Linghuchong("独孤九剑");
fightPeople(xiaoyy);
fightPeople(xiaopp);
fightPeople(xiaoll);
//编译器默认做了一个安全的处理。 编译器认为不管传递的是子类对象还是父类对象
//如果统一执行父类d方法 那么是一定可以被成功执行。
delete xiaoyy;
delete xiaopp;
delete xiaoll;
return 0;
}

10.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
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
#define _CRT_SECUE_NO_WARNING
#include <iostream>

using namespace std;

//英雄类
//1999
class Hero
{
public:
virtual int getAd() {
return 10;
}
};

//1999
class AdvHero :public Hero
{
public:
virtual int getAd()
{
return 1001;
}
};

//怪兽类
//1999
class Monster
{
public:
int getAd() {
return 1000;
}
};

//战斗方法
void playerFight(Hero* hp, Monster* mp)
{
//多态对于编译器来讲的,也是一个动态联编,也是一个迟邦定
if (hp->getAd() > mp->getAd()) { //hp->getAd 发生了多态
cout << "英雄胜利, 怪兽被打死" << endl;
}
else {
cout << "英雄挂了,怪兽赢了" << endl;
}
}

//2020年
class BugHero :public Hero
{
public:
virtual int getAd()
{
cout << "调用了bugHero的方法" << endl;
return 66666;
}
};

int main() {
Hero h;
Monster m;
playerFight(&h, &m);
AdvHero advH;
playerFight(&advH, &m);
BugHero bH;
playerFight(&bH, &m);
int a = 10;
int b = 20;
cout << a << endl;
if (a > 10) { //迟邦定
cout << "a > 10" << endl;
}
else {
cout << "a <= 10" << endl;
}
return 0;
}

10.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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#define _CRT_SECUE_NO_WARNING
#include <iostream>

using namespace std;

class A
{
public:
A() {
cout << "A()..." << endl;
this->p = new char[64];
memset(this->p, 0, 64);
strcpy(this->p, "A String..");
}

virtual void print()
{
cout << "A: " << this->p << endl;
}

virtual ~A() {
cout << "~A()..." << endl;
if (this->p != NULL) {
delete[]this->p;
this->p = NULL;
}
}
private:
char* p;
};

class B :public A
{
public:
B() //此刻会触发A()
{
cout << "B()..." << endl;
this->p = new char[64];
memset(this->p, 0, 64);
strcpy(this->p, "B String..");
}

virtual void print()
{
cout << "B: " << this->p << endl;
}

virtual ~B() {
cout << "~B()..." << endl;
if (this->p != NULL) {
delete[] this->p;
this->p = NULL;
}
}
private:
char* p;
};

void func(A* ap)
{
ap->print();//在此发生多态
}

void deleteFunc(A* ap)
{
delete ap; //此刻ap->~B() //~B() ---> ~A()
}

void test()
{
//A *ap = new A;
//func(ap);
B* bp = new B;
func(bp);

deleteFunc(bp);
}

int main() {
test();
B bObj;
//bObj.~B();
return 0;
}

10.3 重载、重写、重定义

重载一定是同一个作用域下。重定义是发生在两个不同的类中,一个父类,一个子类

  • 普通函数重定义:父类的普通成员函数被子类重写
  • 虚函数重写:如果父类的虚函数,被子类重写,就是虚函数重写,这个函数会发生多态

10.4 多态的实现原理

10.4.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
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>

using namespace std;

class Parent
{
public:
Parent(int a) {
this->a = a;
}

virtual void func(int a)
{
cout << "Parent::func(int)..." << endl;
}

virtual void func(int a, int b, int c)
{
cout << "Parent::func(int ,int ,int )...." << endl;
}
private:
int a;
};

class Child :public Parent
{
public:
Child(int a, int b) :Parent(a)
{
this->b = b;
}
virtual void func(int a)
{
cout << "Child: func(int)..." << endl;
}

void func(int a, int b) {
cout << "Child :func(int ,int )..." << endl;
}

virtual void func(int a, int b, int c)
{
cout << "Child ::func(int ,int ,int )..." << endl;
}
private:
int b;
};

int main(void)
{
//Parent *pp = new Parent(10);
//Parent *cp = new Child(100, 200);
Parent* pp = new Child(100, 200);
pp->func(10);//Parent ? Child
//如果调用一个普通函数,编译器根本就不会查找虚函数表。
//只有你调用的函数,是虚函数的时候,才会去查找虚函数表
pp->func(10, 20, 30);
return 0;
}

10.4.2 验证vptr指针的存在

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
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>

using namespace std;

class Parent
{
public:
virtual void func()
{
cout << "Parent::func().." << endl;
}
virtual void func(int a)
{
cout << "Parent::func().." << endl;
}
private:
int a;
};

class Parent2
{
public:
void func()
{
cout << "Parent2::func().." << endl;
}
private:
int a;
};

int main(void)
{
Parent p1;
Parent2 p2;
cout << "sizeof(p1) " << sizeof(p1) << endl;//多出来的4个字节就是vptr指针所占用的空间。
cout << "sizeof(p2) " << sizeof(p2) << endl;
return 0;
}
  • 本文标题:C++学习笔记
  • 本文作者:馨er
  • 创建时间:2021-02-01 20:10:08
  • 本文链接:https://sjxbbd.vercel.app/2021/02/01/3396fdf77464/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!