抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

总览

封装我该有的(属性)和我该做的(方法)

继承:叫一声爸爸,开启财富之门

多态:我就是我,是不一样的烟火

继承

继承往往表现于概念上的递进关系

1
2
3
4
5
6
7
8
9
10
class Animal {
public :
string name() { return this->__name; }
private :
string __name;
};
// 实现继承的语法 public(继承的权限)
class Cat : public Animal {
// 所有动物类中有的,猫类都有
};

image-20220719092201804

继承的好处:

  • 减少编码量
  • 逻辑清晰

基类\派生类

  • 基类(父类) -> Animal

  • 派生类 -> Cat

后续会在代码中标注基类\派生类

继承-子类的访问权限

子类对于父类的继承权限到底影响什么?

子类继承父类的全部 <- 父类

父类\继承权限 public protected private
public
protected
private
父类\继承权限 public protected private
public public protected private
protected protected protected private
private

继承权限相当于两道们叠加在一起那个更严格就执行那个

继承权限的作用影响的是什么?

影响的是类外对于子类中继承于父类父类中这些属性和方法的访问权限

继承-构造函数

隐士类型转换-逻辑上的递进关系

子类 -> 父类 的隐士类型转换
但是父类到子类是不允许以隐士类型转换的, 也就是说子类一定包含父类但是父类不一定包含子类

无论是Base类的(Base &)引用也好(Base *)指针也好,都可以邦达到所有派生类中A、B、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
BEGINS(test2)

class Base {
public :
Base(string name) : class_name(name) {}
int x;
string class_name;
private :
int y;

};

class A :public Base {

public :
// 显性的调用父类的构造函数、如果没有就默认的调用父类的默认构造函数
A() : Base("class_A") {}
};

class B : public Base {
public :
B() : Base("class_B") {}
};

class C : public Base {
public :
C() : Base("class_C") {}
};

void func(Base &b) {
cout << "input class " << b.class_name << endl;
return ;

}

int main() {
// 子类 -> 父类 的隐士类型转换
// 但是父类到子类是不允许以隐士类型转换的
A a;
B b;
C c;
func(a);
func(b);
func(c);
return 0;
}

ENDS(test2)

BEFINES(test3)

using namespace test2;

void func(Base *b) {
cout << "input class " << b->class_name << endl;
return ;

}

int main() {
// 子类 -> 父类 的隐士类型转换
// 但是父类到子类是不允许以隐士类型转换的
A a;
B b;
C c;
func(&a);
func(&b);
func(&c);
return 0;
}

ENDS(test3)

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

继承的构造顺序

  • 构造

    先是子类调用基类的构造函数,在调用子类子什么的构造函数

    基类 -> 子类

  • 析构

    构造顺序永远和析构顺序是相反先构造一定后析构

​ 先析构子类的属性,在析构父类的

菱形继承

  • 面向对象是允许多继承但是有语言也是不支持的如:

    C#、JAVA -> 不允许多继承

D:方法是调用B类的run方法还是是C类run方法

image-20220719092224512

点我-多继承

继承-拷贝&赋值

拷贝行为:-> 先完成父类的拷贝行为在完成子类的拷贝行为

  • 拷贝构造函数:

    显示调用父类拷贝构造

  • 赋值运算符

    显示调用父类的赋值运算符函数

代码合集

  • 继承访问权限
  • 隐士类型转换
  • 构造&析构-顺序
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
/*************************************************************************
> File Name: 1.Cat.cpp
> Author: 秃头王
> Mail: 1658339000@qq.com
> Created Time: 2022年07月18日 星期一 13时47分00秒
************************************************************************/

#include <iostream>
using namespace std;

#define BEGINS(x) namespace x {
#define ENDS(x) } // end of namespace x

BEGINS(test1)

class Base {

public :
int x;
protected :
int y;
private :
int z;
};

class public_Base : public Base {

public :
void main(){
x = 2; // ok, x public
y = 3; // ok, y protected
// z = 4; // no, z private
}

};

class protected_Base : protected Base {

public :
void main(){
x = 2; // ok, x public
y = 3; // ok, y protected
// z = 4; // no, z private
}

};

class private_Base : private Base {

public :
void main(){
x = 2; // ok, x public
y = 3; // ok, y protected
// z = 4; // no, z private
}

};

int main() {

public_Base a;
a.x = 3; // public(继承) public(父类) - > public (表现出来 的)
// a.y = 4; // public(继承) protected(父类) - > protected
// a.z = 5; // public(继承) private(父类) - > private

protected_Base b;
// b.x = 3; // protected(继承) public(父类) - > protected (表 现出来的)
// b.y = 4; // protected(继承) protected(父类) - > protected
// b.z = 5; // protected(继承) private(父类) - > private

private_Base c;
// c.x = 3; // private(继承) public(父类) - > private (表现出 来的)
// c.y = 4; // private(继承) protected(父类) - > private
// c.z = 5; // private(继承) private(父类) - > private
return 0;
}

ENDS(test1)


BEGINS(test2)

class Base {
public :
Base(string name) : class_name(name) {}
int x;
string class_name;
private :
int y;

};

class A :public Base {

public :
// 显性的调用父类的构造函数、如果没有就默认的调用父类的默认构造函数
A() : Base("class_A") {}
};

class B : public Base {
public :
B() : Base("class_B") {}
};

class C : public Base {
public :
C() : Base("class_C") {}
};

void func(Base &b) {
cout << "input class " << b.class_name << endl;
return ;

}

int main() {
// 子类 -> 父类 的隐士类型转换
// 但是父类到子类是不允许以隐士类型转换的
A a;
B b;
C c;
func(a);
func(b);
func(c);
cout << "sizeof(Base) = " << sizeof(Base) << endl;
cout << "sizeof(A) = " << sizeof(A) << endl;
return 0;
}

ENDS(test2)

BEGINS(test3)

class Base {
public :
Base(string name) : class_name(name) {}
int x;
string class_name;
private :
int y;

};

class A :public Base {

public :
// 显性的调用父类的构造函数、如果没有就默认的调用父类的默认构造函数
A() : Base("class_A") {}
};

class B : public Base {
public :
B() : Base("class_B") {}
};

class C : public Base {
public :
C() : Base("class_C") {}
};

void func(Base *b) {
cout << "input class " << b->class_name << endl;
return ;

}

int main() {
// 子类 -> 父类 的隐士类型转换
// 但是父类到子类是不允许以隐士类型转换的
A a;
B b;
C c;
func(&a);
func(&b);
func(&c);
return 0;
}

ENDS(test3)

// 父类和子类的构造顺序
BEGINS(test4)

class ATTR_BASE {

public :
ATTR_BASE(string name) : name(name) {
cout << "construct : " << name << endl;
}
~ATTR_BASE() {
cout << "destructor : " << name << endl;
}
string name;

};

// 属性
class ATTR1 : public ATTR_BASE {
public :
ATTR1(string name) : ATTR_BASE(name) {}
};

// 属性
class ATTR2 : public ATTR_BASE {
public :
ATTR2(string name) : ATTR_BASE(name) {}
};

class Base {
public :
Base() : attr1("attr1 in Base"), attr2("attr2 in Base") {
cout << "Base constructor done" << endl;
}
~Base() {
cout << "Base destructor done" << endl;
}
private :
ATTR1 attr1;
ATTR2 attr2;
};

class A : Base {

public :
// 显性的调用父类的构造函数
A() : Base(), attr1("attr1 in A"), attr2("attr2 in A") {
cout << "A constructor done" << endl;
}
~A() {
cout << "A destructor done" << endl;
}
private :
ATTR1 attr1;
ATTR2 attr2;

};

int main() {
A a;
return 0;
}

ENDS(test4)

int main() {
// test1::main();
// 隐士类型转换
// test2::main();
// test3::main();
// 构造&析构-顺序
test4::main();
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
/*************************************************************************
> File Name: 2.succeed_copy.cpp
> Author: 秃头王
> Mail: 1658339000@qq.com
> Created Time: 2022年07月18日 星期一 18时07分06秒
************************************************************************/

#include <iostream>
using namespace std;

#define BEGINS(x) namespace x {
#define ENDS(x) } // end of namespace x

BEGINS(test1)

class ATTR_BASE {

public :
ATTR_BASE(string name) : name(name) {
cout << "construct : " << name << endl;
}
~ATTR_BASE() {
cout << "destructor : " << name << endl;
}
ATTR_BASE operator=(const ATTR_BASE &a) {
name = a.name;
cout << "operator= : " << name << endl;
return *this;
}
ATTR_BASE(const ATTR_BASE &a) : name(a.name) {
cout << "default copy constructor : " << name << endl;
}
string name;

};

// 属性
class ATTR1 : public ATTR_BASE {
public :
ATTR1(string name = "none") : ATTR_BASE(name) {}
};

// 属性
class ATTR2 : public ATTR_BASE {
public :
ATTR2(string name = "none") : ATTR_BASE(name) {}
};

class Base {
public :
Base() : attr1("attr1 in Base"), attr2("attr2 in Base") {
cout << "Base constructor done" << endl;
}
Base(const Base &b) : attr1(b.attr1), attr2(b.attr2) {
cout << "Base copy constructor done" << endl;
}
Base &operator=(const Base &b) {
attr1 = b.attr1;
attr2 = b.attr2;
cout << "Base operator= done" << endl;
return *this;
}
~Base() {
cout << "Base destructor done" << endl;
}
private :
ATTR1 attr1;
ATTR2 attr2;
};

class A : Base {

public :
// 显性的调用父类的构造函数
A() : Base(), attr1("attr1 in A"), attr2("attr2 in A") {
cout << "A constructor done" << endl;
}
A(const A &a) : Base(a), attr1(a.attr1), attr2(a.attr2){
cout << "A copy constructor done" << endl;
}
A &operator=(const A &a) {
this->Base::operator=(a); // 调用父类的默认复制运算符
attr1 = a.attr1;
attr2 = a.attr2;
cout << "A operator= done" << endl;
return *this;
}
~A() {
cout << "A destructor done" << endl;
}

private :
ATTR1 attr1;
ATTR2 attr2;

};

int main() {
A a;
cout << " ---------------- default constructor ----------------- " << endl << endl;
A b(a);
cout << " ---------------- copy constructor ----------------- " << endl << endl;
b = a;
cout << " ---------------- operator constructor ----------------- " << endl << endl;
return 0;
}

ENDS(test1)

int main() {
test1::main();
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
#include <iostream>
using namespace std;

#define BEGINS(x) namespace x {
#define ENDS(x) } // end of namespace x
// 不能产生对象的类
BEGINS(test2)

class NoObject {
public :
NoObject() = delete;
NoObject(const NoObject &) = delete;
};

int main() {
NoObject *p = (NoObject *)malloc(sizeof(NoObject));
// NoObject b(*p);
return 0;

}

ENDS(test2)

int main() {
// 多继承
// test1::main();
// 不呢产生对象的类
test2::main();
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
/*************************************************************************
> File Name: 3.multi_succeed.cpp
> Author: 秃头王
> Mail: 1658339000@qq.com
> Created Time: 2022年07月18日 星期一 22时09分02秒
************************************************************************/

#include <iostream>
using namespace std;

#define BEGINS(x) namespace x {
#define ENDS(x) } // end of namespace x

BEGINS(test1)

class A {
protected :
A() : x(9973) {}
int x;
};

class B : public A {

public :
void setX(int x) {
cout << "set x : " << &(this->x) << endl;
this->x = x;
return ;
}

};

class C : public A {

public :
int getX() {
cout << "get x : " << &(this->x) << endl;
return this->x;
}

};

class D : public B, public C {

};

int main() {
D d;
cout << d.getX() << endl;
d.setX(10000);
cout << d.getX() << endl;
return 0;

}

ENDS(test1)

int main() {

test1::main();

return 0;
}

image-20220719125815524

内存存储区-虚继承

虚继承: 当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
/*************************************************************************
> File Name: 3.multi_succeed.cpp
> Author: 秃头王
> Mail: 1658339000@qq.com
> Created Time: 2022年07月18日 星期一 22时09分02秒
************************************************************************/

#include <iostream>
using namespace std;

#define BEGINS(x) namespace x {
#define ENDS(x) } // end of namespace x

BEGINS(test1)

class A {
protected :
A() : x(9973) {}
int x;
};

class B : virtual public A {

public :
void setX(int x) {
cout << "set x : " << &(this->x) << endl;
this->x = x;
return ;
}

};

class C : virtual public A {

public :
int getX() {
cout << "get x : " << &(this->x) << endl;
return this->x;
}

};

class D : public B, public C {

};

int main() {
D d;
cout << d.getX() << endl;
d.setX(10000);
cout << d.getX() << endl;
return 0;

}

ENDS(test1)

int main() {

test1::main();

return 0;
}

image-20220719140958028

功能类配合重载、不能被拷贝行为

功能类配合重载可以通过继承标记某个类的性质

STL中类型萃取就是用的这种编程技巧

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
/*************************************************************************
> File Name: 4.uncopyable.cpp
> Author: 秃头王
> Mail: 1658339000@qq.com
> Created Time: 2022年07月19日 星期二 14时28分05秒
************************************************************************/

#include <iostream>
using namespace std;

#define BEGINS(x) namespace x {
#define ENDS(x) } // end of namespace x

BEGINS(test1)

// 功能类
class UNCOPYABLE {

public :
// 默认构造不能删除掉要不A类的默认也就没有了
// UNCOPYABLE() = delete;
UNCOPYABLE(const UNCOPYABLE &) = delete;
UNCOPYABLE &operator=(const UNCOPYABLE &) = delete;
UNCOPYABLE &operator=(const UNCOPYABLE &) const = delete;
protected :
UNCOPYABLE() = default;

};

// 标记类的性质 A 不能被拷贝
class A : public UNCOPYABLE {

public :

};

int main() {
A a;
A b;
// b = a; // no, operator= delete
// A b(a); // no, copy construtor delete
return 0;
}

ENDS(test1)

BEGINS(test2)

// 功能类
class HAS_XY {

public :
int x, y;
};

class HAS_XYZ : public HAS_XY {

public :
int z;
};

class A : public HAS_XY {
public :
A() {
x = y =1;
}
};
class B : public HAS_XY {
public :
B() {
x = y = 2;
}
};
class C : public HAS_XYZ {
public :
C() {
x = y = z = 3;
}
};
class D : public HAS_XY {
public :
D() {
x = y = 4;
}
};
class E : public HAS_XYZ {
public :
E() {
x = y = z = 5;
}
};

void func(HAS_XY &a) {
cout << "has xy : ";
cout << a.x << ", " << a.y << endl;
return ;
}

void func(HAS_XYZ &a) {
cout << "hax_xyz : ";
cout << a.x << ", " << a.y << ", " << a.z << endl;
return ;
}

int main() {
A a;
B b;
C c;
D d;
E e;
func(a);
func(b);
func(c);
func(d);
func(e);
return 0;
}

ENDS(test2)

int main() {
// 不能被拷贝行为 -> 拷贝构造、复制运算
// test1::main();
// 标记每一种类的性质
// 配合重载就可以针对处理每种性质的类
test2::main();
return 0;
}

源码文件*.cpp

点我跳转:https://github.com/qzwl123/C-/tree/main/%E7%BB%A7%E6%89%BF

评论