文章目录
引言
这篇博客本来在上个月就应该发出来,但是中间由于各种原因,而一拖再拖,今天也终于完成了这篇博客,
各位看官请好好欣赏吧
继承的概念与定义
继承是对代码进行复用,是类设计层次的复用,让我们的子类可以使用父类的代码,减少代码的冗余提高效率
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class strudent { string name; string id; string address;
}
class teacher { string name; string id; string address;
}
|
我们会发现这虽然这是两种不同的类,但是有很多信息是重复冗余的
所以我们完全可以定义个父类,来保存共有的信息
如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class person { string name; string id; string address; } 继承person的 class student:public person { private:
} class teacher:public person { 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
| #include<iostream> using namespace std; class Person { public: void Print() { cout << "name:" << _name << endl; cout << "age:" << _age << endl; } protected: string _name = "peter"; int _age = 18; };
class Student : public Person { protected: int _stuid; }; class Teacher : public Person { protected: int _jobid; }; int main() { Student s; Teacher t; s.Print(); t.Print(); return 0; }
|
继承的模板
1
| class student :public person
|
继承的定义
class默认是公有继承(但是我们最好把继承方式写上)
- 格式
class student :public person
student是派生类,public是继承方式,person是基类
- 继承关系与访问限定符
继承方式
:public继承,protect继承,private继承
访问限定符
:public访问,protect访问,private访问

- 基类的private成员在派生类中无论以什么方式继承都是不可以见到的
数据继承下来了,在那个地方但是用不上,不可以见的意思是
:继承下来之后,不管是在类的里面还是在类的外面都不可以访问他
继承:简单粗暴,直接全部继承下来,但是无论如何都永不上这个成员的
不想给子类用就定义成private,想给子类用就定义成public或者protected
取访问限定符和访问方式中的小的那一个
public>protect>private
public和protect和private的区别
public想让别人可以直接使用
protect不想要让别人直接使用,但是想要让子类能够使用
private不想让任何人使用,包括子类
保护和私有在父类中没有区别
4.在实际使用的过程中,一般都是public继承,几乎很少private和protect,不提倡private和protect继承,
在类里面基本都使用protect和public,几乎不使用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
| class person { protected: string _sex; string _name; int _age; };
class student : public person { public: int _no; };
int main() { person p; student s; p=s; person*ptr=&s; person& ref=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
| class student : public person { public: int _no = 1; void Print() { cout << _no; cout << person::_no << endl; } };
int main() { person p; student s; s.Print(); s.person::Print();
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 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
| #include <string> #include<iostream> using namespace std;
class Person { public: Person(const char *name ) : _name(name) { cout << "person()" << endl; } Person(const Person &s) : _name(s._name) { cout << "person(const person& s)" << endl; } Person &operator=(const Person &s) { cout << "Person=" << endl; if (this != &s) { _name = s._name; } return *this; } ~Person() { cout << "~Person()" << endl; }
protected: string _name; };
class Student : public Person { public: Student(const char *s = "zhans", int num = 1) : Person(s) , _num(num) {}
Student(const Student &s) : Person(s) , _num(s._num) { }
Student &operator=(Student &s) { if (this != &s) { _num = s._num;
Person::operator=(s); } }
#if 0 ~Student() { }
#endif
private: int _num = 1; };
int main() { Student s; return 0; }
|
复杂的菱形继承与
多继承就是一个坑,
单继承:一个类只有一个直接父类
多继承,一个类有多个直接父类

菱形继承是多继承的一种特殊情况,多继承没问题,只不过要避免菱形继承

存在数据冗余和二义性
里面有两份person
先继承前面的,再继承后面的

A一般叫做虚基类
再D里面,A放到一个公共的位置,那么有时候B需要找A,C 需要找A,就需要通过虚基表中的偏移量进行计算
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
| class A { public: int _a; };
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::_a = 1; d.C::_a = 2; d._b = 4; d._c = 5; d._d = 6;
return 0; }
|
我们尽量不要定义出菱形继承,虚继承
继承的总结和反思
c++的缺陷
- 没有垃圾回收器
- 多继承
继承和组合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
class a {} class b:public a {}
class c { int_c }
class d { C _obj; int _d }
|
- public继承是一种is_a 的关系,也就是说每个派生类的对象都是一种基类对象,b就是一个a
Student 和Person的关系就适合用继承 ,Student is Person
- 组合是一种has_a的关系,b组合了A,那么就是说b里面有一个a对象
眼睛和头的关系,就适合用组合,头上有眼睛
车和轮胎的关系,车上有轮胎
- 如果它既是is_a 又可以是has_a,那么优先使用has_a(组合)
继承是白箱服用(能看到它的实现细节),组合是黑箱服用(看不见它的实现细节),所以黑盒测试
除了父类的私有成员,其他子类都是可以进行使用的,这样会破坏基类的封装,子类可能会调用父类的公有成员和保护成员,D只能用C 的公有,不能
类和类之间:低耦合,高内聚(跟我没关系的东西,不要设计进来),
类和类之间 的依赖程序低,方便我们维护,所以组合的耦合程度低,
组合下来,保护的成员也是无法使用的
组合关系之间依赖关系小,关联程度低,修改很方便,可维护性强
切割和切片就是继承的好处
而多态就是建立在继承的基础之上,