C++面向对象拓展

2

C++面向对象拓展

  C++面向对象还有一部分拓展知识,包括运算符重载以及多继承产生的问题,也可以给最终章的虚函数做一个铺垫,在这里给大家做简单的介绍。

运算符重载

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;

class Person {

public:
string name;
int age;
int money;

Person(string name, int age, int money) {
this->name = name;
this->age = age;
this->money = money;
}

//operator加上要重载的运算符,称为运算符重载。
//在这里重载+运算符,两个对象之间不能进行运算,但是重载了加号运算符之后,可以根据重载的内容实现两个对象的加法运算。
int operator+(Person& p) {
return this->money + p.money;
}

//在这里重载==运算符,两个对象之间不能进行运算,但是重载了等于号运算符之后,可以根据重载的内容判断两个对象是否相等。
bool operator==(Person& p) {
return this->age == p.age;
}
};


int main() {

Person p1("C++程序员", 28, 28000);
Person p2("Python程序员", 22, 22000);

cout << "我的名字是:" << p1.name << " 我的年龄是:" << p1.age << " 我的工资是:" << p1.money << endl;
cout << "我的名字是:" << p2.name << " 我的年龄是:" << p2.age << " 我的工资是:" << p2.money << endl;

//重载后加法计算两个对象的money成员变量之和,因此会输出50000
cout << "我们的工资总数为:" << p1 + p2 << endl;;
//重载等于号判断两个对象的年龄是否相等,因此会返回0
cout << "我们的年龄是否相等:" << (p1 == p2) << endl;

return 0;
}

1

C++多继承

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
#include<iostream>
using namespace std;

class A {
public:
//A类中包括name和a两个成员变量和A的有参构造函数,以及getName成员方法
string name;
int a;

A(string name, int a) {
this->name = name;
this->a = a;
}

string getName() {
return name;
}
};

class B {
public:
//B类中包括name和b两个成员变量和B的有参构造函数,以及getName成员方法
string name;
int b;

B(string name, int b) {
this->name = name;
this->b = b;
}

string getName() {
return name;
}
};

class C:public A, public B{
public:
//C类中包括name和c两个成员变量和C的有参构造函数,以及getName成员方法
//C继承A也继承B,因此同时拥有A和B的成员,但是A和B的同名成员,需要使用作用域进行区分,如果子类也具有同名成员,则会覆盖父类的同名成员。
string name;
int c;

//注意子类构造函数的写法,在参数列表后面加冒号,并写调用父类的构造函数,和Java,Python不同。
C(string name_a, int a, string name_b, int b, string name_c, int c) :A(name_a, a), B(name_b, b) {
this->name = name_c;
this->c = c;
}

string getName() {
return name;
}

};
int main() {

C c("A", 1, "B", 2, "C", 3);
//对象c拥有类A的成员变量a
cout << "c.a = " << c.a << endl;
//对象c拥有类B的成员变量b
cout << "c.b = " << c.b << endl;
//对象c拥有类C的成员变量c
cout << "c.c = " << c.c << endl;

//类C拥有和父类同名的成员变量name,因此子类的成员变量会覆盖父类
cout << "c.name = " << c.name << endl;
//类C拥有和父类同名的成员方法getName,因此子类的成员方法会覆盖父类
cout << "c.getName() = " << c.getName() << endl;
//类C拥有和类A同名的成员变量name,因此要想访问类A的成员变量,需要加入作用域
cout << "c.A::name = " << c.A::name << endl;
//类C拥有和类A同名的成员方法getName,因此要想访问类A的成员方法,需要加入作用域
cout << "c.A::getName() = " << c.A::getName() << endl;
//类C拥有和类B同名的成员变量name,因此要想访问类B的成员变量,需要加入作用域
cout << "c.B:::name = " << c.B::name << endl;
//类C拥有和类B同名的成员方法getName,因此要想访问类B的成员方法,需要加入作用域
cout << "c.B::getName() = " << c.B::getName() << endl;
//类C拥有和父类同名的成员变量name,因此子类默认调用自己的成员变量,c.C::name等价于c.name
cout << "c.C::name = " << c.C::name << endl;
//类C拥有和父类同名的成员方法getName,因此子类默认调用自己的成员方法,c.C::getName等价于c.getName
cout << "c.C::getName() = " << c.C::getName() << endl;

return 0;

}

1

C++菱形继承——解决方案

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
#include<iostream>
using namespace std;

class A {
public:
string name;
int a;
};

class B :public A {
public:
int b;
};

class C :public A {
public:
int c;
};

//D类继承B和C类,然而B和C都继承A类,构成了一种菱形继承关系。
//A类中的name成员变量,在D中的name不知道是从B中继承而来的还是从C中继承而来的
class D :public B, public C {
public:
int d;
};

int main() {

D d;
//访问时和之前说过的一样,可以通过指定作用域来实现对哪一个父类的成员变量进行访问。
//但是不可以直接使用d.name,这就编译器不知道是从哪一个类继承而来的成员变量,会报错。
d.B::name = "B";
d.C::name = "C";

cout << "d.B::name = " << d.B::name << endl;
cout << "d.C::name = " << d.C::name << endl;

return 0;

}

1

C++菱形继承——解决方案

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 A {
public:
string name;
int a;
};

//对于上面发生的问题,通过在继承前面加上virtual关键字,代表虚继承。
//小伙伴们可以理解为B和C不再保存A中的具体内容,而是保存了一份偏移地址。
//当调用d.B::name时,会指向d.A::name,当调用d.C::name时,也会指向d.A::name,当调用d.name时也会指向d.A::name。
class B :virtual public A {
public:
int b;
};

class C :virtual public A {
public:
int c;
};

class D :public B, public C {
public:
int d;
};

int main() {

D d;
d.B::name = "B";
d.C::name = "C";

//因此d.B::name和d.C::name和d.name都是相同的结果。
cout << "d.B::name = " << d.B::name << endl;
cout << "d.C::name = " << d.C::name << endl;
cout << "d.name = " << d.name << endl;

d.name = "D";

cout << "d.B::name = " << d.B::name << endl;
cout << "d.C::name = " << d.C::name << endl;
cout << "d.name = " << d.name << endl;

return 0;

}

1

C++小结

  今天的内容是C++面向对象的拓展部分,比较重要的部分是运算符的重载,在后面STL中可能会再次见到它,而菱形继承方式,我们在使用面向对象时,要尽量避免碰到它。

-------------本文结束感谢您的阅读-------------
0%