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

using namespace std;

class Person {
private:
int x, y;

public:
Person(int x, int y) : x(x), y(y) {};

void setX(int x) {
this->x = x;
}

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

void setY(int y) {
this->y = y;
}

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

// 类里重载操作符
Person operator+(Person person2) {
int x = this->x + person2.getX();
int y = this->y + person2.getY();

Person res(x, y);
return res;
}

// 正规写法
// 使用const person2为只读
// 使用& 直接引用,不构建新副本。性能考虑!
Person operator+(const Person & person2) {
int x = this->x + person2.x;
int y = this->y + person2.y;

Person res(x, y);
return res;
}

// 重载 ++
// ++对象
void operator ++ (){
this->x = this->x + 1;
this->y = this->y + 1;
}

// 对象++
void operator ++ (int){
this->x = this->x + 1;
this->y = this->y + 1;
}

// 自定义输出对象
// istream 输入
// ostream 输出
// 输出单个
friend void operator << (ostream & _START, const Person & person) {
_START << person.x << "--" << person.y << endl;
}

// 输出多个对象。ostream &表示循环遍历
/*
friend ostream & operator << (ostream & _START, const Person & person) {
_START << person.x << "--" << person.y << endl;
return _START; // 返回一直输出
}*/

// 输入
friend istream & operator >> (istream & _START, const Person & person) {
_START >> person.x;
_START >> person.y;

// _START >> person.x >> person.y; // 也可以这么写
return _START;
}
};

// 写到类外面需要两个参数,类里面只需要写一个参数
// 重载加号 operator重载关键字。一般操作符重载写到内部!!!
Person operator+(Person person1, Person person2) {
int x = person1.getX() + person2.getX();
int y = person1.getY() + person2.getY();

Person res(x,y);
return res;
}

int main() {
Person person1(10, 20);
Person person2(30, 40);

Person person3 = person1 + person2;

cout << "x:" << person3.getX() << "y:" << person3.getY() << endl;

// 自定义输出对象
cout << person1;

// 输出多个
cout << person1 << person1 << person1 << person1 << person1;
}

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
// 3.括号运算符。   数组 系统源码把此括号[i]给重载,  系统重载后的样子 *(arr+i)

#include <iostream>
using namespace std;

// 写一个小容器,模拟容器
class ArrayClass {

private:
// C++ 默认都是系统值 size 系统值 -13275
int size = 0; // 大小 开发过程中,给size赋默认值,不然会出现,后患无穷的问题
int * arrayValue; // 数组存放 int 类型的很多值

public:
void set(int index, int value) {
arrayValue[index] = value; // []目前不是我的
size+=1;
}
int getSize() { // size成员的目标:是为了循环可以遍历
return this->size;
}
// 运算符重载 [index]
int operator[](int index) {
return this->arrayValue[index]; // 此[]是系统的
}
};

// 输出容器的内容
void printfArryClass(ArrayClass arrayClass) {
cout << arrayClass.getSize() << endl;
for (int i = 0; i < arrayClass.getSize(); ++i) {
cout << arrayClass[i] << endl; // []是我们自己的 重载符号
}
}

int main() {
// 能在栈区的,尽量在栈区
// 1.代码量少
// 2.避免麻烦
// 3.怕有问题
// 4.栈区的回收,不是你负责的,责任推卸

//目前arrayClass对象是在栈区 实例出来的对象,是在堆区了
ArrayClass arrayClass;

arrayClass.set(0, 1000);
arrayClass.set(1, 2000);
arrayClass.set(2, 3000);
arrayClass.set(3, 4000);
arrayClass.set(4, 5000);

printfArryClass(arrayClass);

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

using namespace std;

class Person {
public:
char *name;
int age;

public:
Person(char *name, int age) : name(name) {
this->age = age;
cout << "Person 构造函数" << endl;
}

void print() {
cout << this->name << " , " << this->age << endl;
}
};

// 1.默认是 隐式代码: : private Person
// 2.私有继承:在子类里面是可以访问父类的成员,但是在类的外面不行
// 3.必须公开继承,才可以访问父类的成员
class Student : public Person {

// 类 默认是私有的,在子类内部可以对父类进行访问

private:
char * course;

public:
// :父类 , 给自己子类成员初始化
Student(char * name, int age, char* course) : Person(name, age) , course(course) {
cout << "Student 构造函数" << endl;
}

void test() {
cout << name << endl;
cout << age << endl;
print();
}
};

int main() {
Student stu("李元霸", 99, "C++");

// 公开继承,才可以拿父类的成员
stu.name = "李四";

return 0;
}

4. C++多继承

在JAVA语言中只能单继承,可以多实现,很好解决了二义性。但是在C++中是支持多继承的,因此就会出现二义性,下面我们来看一下C++中是如何解决二义性的。

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
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 BaseActivity1 {
public:
void onCreate() {
cout << "BaseActivity1 onCreate" << endl;
}

void onStart() {
cout << "BaseActivity1 onStart" << endl;
}

void show() {
cout << "BaseActivity1 show" << endl;
}
};

class BaseActivity2 {
public:
void onCreate() {
cout << "BaseActivity2 onCreate" << endl;
}

void onStart() {
cout << "BaseActivity2 onStart" << endl;
}

void show() {
cout << "BaseActivity2 show" << endl;
}
};

class BaseActivity3 {
public:
void onCreate() {
cout << "BaseActivity3 onCreate" << endl;
}

void onStart() {
cout << "BaseActivity3 onStart" << endl;
}

void show() {
cout << "BaseActivity3 show" << endl;
}
};

// 子类 继承 三个父类
class MainActivity1 : public BaseActivity1, public BaseActivity2, public BaseActivity3 {
public:
void onCreate() {
cout << "MainActivity1 onCreate" << endl;
}

void onStart() {
cout << "MainActivity1 onStart" << endl;
}

void showSonInfo() {
cout << "MainActivity1 showSonInfo" << endl;
}

// 解决方案二: 子类上 重写父类的show函数
void show() {
cout << "MainActivity1 show" << endl;
}

};

int main() {
// 这个是优先寻找子类的函数,因为特别明确,没有问题,还没有产生歧义(二义性)
MainActivity1 mainActivity1; // 子类
mainActivity1.onCreate();
mainActivity1.onStart();
mainActivity1.showSonInfo();

// error: request for member 'show' is ambiguous
// 不明确,二义性,歧义
// mainActivity1.show(); 必须在子类中重写父类的方法,才可以解决二义性

// 解决方案一: 明确指定父类 ::
mainActivity1.BaseActivity3::show();
mainActivity1.BaseActivity2::show();
mainActivity1.BaseActivity1::show();

// 解决方案二: 子类上 重写父类的show函数
mainActivity1.show();

return 0;
}
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
#include <iostream>

using namespace std;

// 祖父类
class Object {
public:
int number;
};

// 父类1
class BaseActivity1 : public Object {

};

// 父类2
class BaseActivity2 : public Object {

};

// 子类
class Son : public BaseActivity1, public BaseActivity2 {

// 第二种解决方案: 在类中定义同名成员,覆盖掉父类的相关成员
public:
int number;

};


int main() {
Son son;

// error: request for member 'show' is ambiguous 二义性 歧义
// son.number = 2000;

// 第一种解决方案: :: 明确指定
son.BaseActivity1::number = 1000;
son.BaseActivity2::number = 1000;

// 第二种解决方案: 在类中定义同名成员,覆盖掉父类的相关成员
son.number = 3000;

return 0;
}
4.3使用虚函数来过渡继承

使用虚继承可以为所欲为的玩。

使用virtual修饰的继承,子类不能重写父类的属性和方法。所有都共用一份。

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 Object{
public:
int number;
void show() {
cout << "Object show run..." << endl;
}
};

// 父类1
class BaseActivity1 : virtual public Object {
// public:int number; // 人为制作二义性 error: request for member 'number' is ambiguous
};

// 父类2
class BaseActivity2 : virtual public Object {
// public:int number;
};

// 子类
class Son : public BaseActivity1, public BaseActivity2 {

};

int main() {
Object object;
BaseActivity1 baseActivity1;
BaseActivity2 baseActivity2;
Son son;

object.number = 100;
baseActivity1.number = 200;
baseActivity2.number = 300;
son.number = 400;

object.show();
baseActivity1.show();
baseActivity2.show();
son.show();

cout << object.number << endl;
cout << baseActivity1.number << endl;
cout << baseActivity2.number << endl;
cout << son.number << endl;

return 0;
}