继承概念

继承是一种面向对象编程的重要概念,它允许一个类(称为派生类,父类)继承另一个类(称为基类,子类)的特性和行为。

1
2
3
4
class B : 继承方式 A//A类为父类,B类为子类
{

};

继承方式:
公有继承(public)
私有继承(private)
保护继承(protected)

继承的特点:
通过继承,派生类可以获得基类的成员变量和成员函数,并且可以添加自己的新成员变量和成员函数。这样可以实现代码的复用和扩展

继承使用场景:
当多个类之间有相同的属性和方法时,可以将这些共同的部分抽取出来,放在一个基类中,然后其他类通过继承基类来复用这些代码。

继承方式

权限修饰符及其作用范围

权限修饰符:用来限制类中的成员(成员变量、成员方法…)能够被访问的范围。

修饰符 本类里 子孙类 外部类
public
protected
private

三种继承方式

(1)公有继承(public)
(2)保护继承(protected)
(3)私有继承(private)

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
#include <iostream>
using namespace std;
class Father
{
public:
int a;
protected:
int b;
private:
int c;
public:
void fun1()
{
cout << "父类的公共方法" << endl;
}
protected:
void fun2()
{
cout << "父类的受保护方法" << endl;
}
private:
void fun3()
{
cout << "父类的私有方法" << endl;
}
};
class Son1:public Father//公有继承(全部)
{
public:
void fun()
{
a = 10;
b = 20;
//c = 30;//报错:父类私有,子类不能访问

fun1();
fun2();
//fun3();//报错:父类私有,子类不能访问
}
};
class Son2:protected Father//保护继承(本类和子类)
{
public:
void fun()
{
a = 10;//protected 权限降级
b = 20;//protected
//c = 30;//报错:父类私有,子类不能访问

fun1();//protected权限降级
fun2();//protected
//fun3();//报错:父类私有,子类不能访问
}
};
class Son3:private Father
{
public:
void fun()
{
a = 10;//private 权限降级
b = 20;//private
//c = 30;//报错:父类私有,子类不能访问

fun1();//private权限降级
fun2();//private
//fun3();//报错:父类私有,子类不能访问
}
};
int main()
{
Son s1;
s1.a = 10;//父类的a是public,子类可以使用,其他类也可以使用
//s1.b = 20;//父类的b是protected,子类可以使用,其他类不能使用
//s1.c = 30;
s1.fun();

Son s2;
//s2.a = 10; //a在子类中已经降级为protected
//s2.b = 20;
//s2.c = 30;
s2.fun();

Son s3;
//s3.a = 10; //a在子类中已经降级为private
//s3.b = 20;//private
//s3.c = 30;
s3.fun();
return 0;
}

继承后子类的构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Person
{
private:
string name;
int age;
public:
Person():name{},age{}{}
Person(string name,int age):name{name},age{age}{}
};
class Student:public Person
{
private:
int number;
public:
Student():Person{},number{}{}
Student(string name,int agem,int number):Person{name,age},number{number}{}
};

继承中的对象模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Father
{
public:
int a;
protected:
int b;
private:
int c;
};
class Son:private Father
{
};
int main()
{
Son s;
cout << "sizeof Son = " << sizeof(Son) << endl;//12
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
class Father
{
public:
Father()
{
cout << "父类的构造函数" << endl;//1
}
~Father()
{
cout << "父类的析构函数" << endl;//4
}
};
class Son:public Father
{
public:
public:
Son()
{
cout << "子类的构造函数" << endl;//2
}
~Son()
{
cout << "子类的析构函数" << endl;//3
}
};
int main()
{
Son s;
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
#include <iostream>
using namespace std;
class Father
{
public:
int m_A;
Father()
{
m_A = 100;
}
void fun()
{
cout << "Father-fun" << endl;
}
void fun(int a)
{
cout << "Father-fun(int a)" << endl;
}
};
class Son:public Father
{
public:
int m_A;
Son()
{
m_A = 200;
}
void fun()
{
cout << "Son-fun" << endl;
}
void fun(int a)
{
cout << "Son-fun(int a)" << endl;
}
};
int main()
{
Son s;
cout <<"Son:"<<s.m_A << endl;//200
cout <<"Father:"<<s.Father::m_A << endl;//100
s.fun();
s.fun(2);
s.Father::fun();
s.Father::fun(3);
return 0;
}

总结:
(1)子类对象可以直接访问到子类中同名成员
(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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>
using namespace std;
class Father
{
public:
static int m_A;
static void fun()
{
cout << "Father-fun" << endl;
}
static void fun(int a)
{
cout << "Father-fun(int a)" << endl;
}
};
int Father::m_A = 100;

class Son:public Father
{
public:
static int m_A;
static void fun()
{
cout << "Son-fun" << endl;
}
static void fun(int a)
{
cout << "Son-fun(int a)" << endl;
}
};
int Son::m_A = 200;
int main()
{ //通过对象访问
Son s;
cout <<"Son:"<<s.m_A << endl;//200
cout <<"Father:"<<s.Father::m_A << endl;//100
s.fun();
s.fun(2);
s.Father::fun();
s.Father::fun(3);

//通过类访问
cout <<"Son:"<<Son::m_A << endl;//200
cout <<"Father:"<<Father::m_A << endl;//100
Son::fun();
Son::fun(2);
Father::fun();
Father::fun(3);
return 0;
}

总结:同名静态成员处理方式和非静态处理方式一样,只不过有两种访问的方式(通过对象名 和 通过类名)

深入了解:
(1)局部变量添加static,改变变量的存储区域,从栈–静态/全局区,导致静态变量的生命周期发生变化,作用域不变
(2)类中的static变量属于类,不属于类中的对象
(3)类中的static变量,在类内声明,类外初始化

多继承与菱形继承

多继承语法

1
2
3
class 子类 : 继承方式 父类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
class Father1
{
public:
int m_A;
Father1()
{
m_A = 10;
}
};
class Father2
{
public:
int m_B;
Father2()
{
m_B = 20;
}
};
class Son:public Father1,public Father2
{
public:
int m_C;
int m_D;
Son()
{
m_C = 30;
m_D = 40;
}
};
int main()
{
Son s;
cout << "sizeof(Son) = " <<sizeof(Son) << endl;//16
cout << "s.m_A = " <<s.m_A << endl;
cout << "s.m_B = " <<s.m_B << endl;
cout << "s.m_C = " <<s.m_C << endl;
cout << "s.m_D = " <<s.m_D << 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
class Father1
{
public:
int m_A;
Father1()
{
m_A = 10;
}
};
class Father2
{
public:
int m_A;
Father2()
{
m_A = 20;
}
};
class Son:public Father1,public Father2
{
public:
int m_C;
int m_D;
Son()
{
m_C = 30;
m_D = 40;
}
};
int main()
{
Son s;
cout << "sizeof(Son) = " <<sizeof(Son) << endl;//16
cout << "s.Father1::m_A = " <<s.Father1::m_A << endl;
cout << "s.Father2::m_A = " <<s.Father2::m_A << endl;
cout << "s.m_C = " <<s.m_C << endl;
cout << "s.m_D = " <<s.m_D << endl;
return 0;
}

总结: 多继承中如果父类中出现了同名情况,子类使用时候要加作用域

菱形继承

概念:
1、两个派生类继承同一个基类
2、又有某个类同时继承两个派生类这种继承被称为菱形继承,或者钻石继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Animal{
public:
int m_Age;
};
class Sheep:public Animal{};
class Tuo:public Animal{};
class SheepTuo:public Sheep,public Tuo{};
int main()
{
SheepTuo st;
//st.m_Age = 10;//报错不明确
st.Sheep::m_Age = 20;
st.Tuo::m_Age = 30;
return 0;
}

解决菱形继承二义性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
using namespace std;
class Animal{
public:
int m_Age;
};
//继承前加virtual关键字后,变为虚继承
//此时公共的父类Animal变为虚基类
class Sheep:virtual public Animal{};
class Tuo:virtual public Animal{};
class SheepTuo:public Sheep,public Tuo{};
int main()
{
SheepTuo st;
st.m_Age = 10;
st.Sheep::m_Age = 20;
st.Tuo::m_Age = 30;
cout << "st.m_Age = " << st.m_Age << endl;
return 0;
}