继承概念
继承是一种面向对象编程的重要概念,它允许一个类(称为派生类,父类)继承另一个类(称为基类,子类)的特性和行为。
继承方式:
公有继承(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;
fun1(); fun2(); } }; class Son2:protected Father { public: void fun() { a = 10; b = 20;
fun1(); fun2(); } }; class Son3:private Father { public: void fun() { a = 10; b = 20;
fun1(); fun2(); } }; int main() { Son s1; s1.a = 10; s1.fun(); Son s2; s2.fun(); Son s3; 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; 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; } ~Father() { cout << "父类的析构函数" << endl; } }; class Son:public Father { public: public: Son() { cout << "子类的构造函数" << endl; } ~Son() { cout << "子类的析构函数" << endl; } }; 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; cout <<"Father:"<<s.Father::m_A << endl; 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; cout <<"Father:"<<s.Father::m_A << endl; s.fun(); s.fun(2); s.Father::fun(); s.Father::fun(3);
cout <<"Son:"<<Son::m_A << endl; cout <<"Father:"<<Father::m_A << endl; 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; 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; 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.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; };
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; }
|