一、继承
继承是使代码复用的一种机制。(本质)
单继承:一个派生类一个基类派生。
多继承:一个派生类有两个人或者多个基类。(如:马与驴杂交所生的骡子就有两个基类,骡子既继承了马的一些特征,也继承了驴的一些特征)
派生类
构造派生类包括:
1、从基类接收成员;(派生类接收基类的全部成员,没有选择)
2、调整从基类接收的成员;(可以改变基类成员在派生类中的访问属性(通过继承的方式实现))
3、在声明派生类时增加的成员(体现派生类对基类功能的扩展)
#include<iostream> #include<algorithm> #include<string> #if0 class Base { public: Base(int a) :ma(a){} protected: int ma; }; class Derive:public Base //派生了Derive { public: Derive(int b) :mb(b), Base(b) { } private: int mb; }; int main() { Derive d(10); return 0; } #endif class People { public: typedef int a; public: People(std::string name = "", int age = 0, bool sex = true) : mname(name), mage(age), msex(sex){} void eat() { std::cout << mname << " is eating!" << std::endl; } void sleep() { std::cout << mname << "is sleepping" << std::endl; } void play(std::string name) { std::cout << mname << " is playing " << name << std::endl; } static void Show() { std::cout << "hello world!" << std::endl; } static int count; protected: std::string mname;//28 int mage;//4 bool msex;//1 }; int People::count = 0; class Student:public People { public: Student(std::string name, int age, bool sex, std::string id) :People(name,age,sex) { mid = id; } private: std::string mid; }; int main() { std::cout << sizeof(People) << std::endl; std::cout << sizeof(Student) << std::endl; Student stu("zhangsan", 18, false, "x0001"); stu.eat(); stu.Show(); Student::a b = 10; return 0; } 继承与派生类的关系:派生类是基类的具体化,而基类是派生类的抽象。
特点:
1、派生类继承了基类的什么东西?
2、继承方式:public、private、protected
3、访问限定符:
public:在任意位置可见;
private:在本类类中访问;
protected:在本类类中和子类类中。
基类中不同访问限定符下的成员以不同的继承方式继承后在派生类中的访问情况:
| public | protected | private | |
|---|---|---|---|
| public | public | protected | 不可访问 |
| protected | protected | protected | 不可访问 |
| private | private | private | 不可访问 |
(1)类和类的关系:
3、代理关系;
举例:
class A//基类 { public: A(){} public: int ma; protected: int mb; private: int mc; }; class B : private A /*protected/private继承是一个实现继承, 基类的部分成员 并非完全成为子类接口 的一部分, 是 has-a 的关系原则, 所以非特殊情况下不会使用这两种继承关系, 在绝大多数的场景下使用的 都是公有继承。 基类的private成员 在派生类中是不能被访问的, 如果基类成员 不想在类外直接被访问, 但需要 在派生类中能访问, 就定义为protected。 可以看出保护成员 限定符是因继承才出现的。*/ { //mb protected //mb private //mc 不可见 public: B(){} void Show() { std::cout << mb << std::endl; } }; class C :public B // public继承是一个接口继承,保持is-a原则,每个父类可用的成员对子类也可用, 因为每个子类对象也都是一个父类对象。 { public: C(){} void Show() { //std::cout << mb << std::endl; } }; int main() { B b; C c; //std::cout << b.mb << std::endl; b.Show(); c.Show(); /*std::cout << sizeof(A) << std::endl; std::cout << sizeof(B) << std::endl;*/ return 0; } (2)同名函数的关系:
1、重载 overload
隐藏了基类中所有同名函数。(隐藏:继承关系、同名)
派生类中同名同参的虚函数覆盖基类中同名同参的虚函数
(3)基类和派生类指针或者引用的相互指向或者引用
允许基类指针指向或者引用派生类对象;
不允许派生类指针指向或者引用基类对象;
(4)派生类的构造和析构顺序(先构造后析构)
构造顺序:
1、调用基类构造函数,对基类数据成员初始化;
2、调用子对象构造函数,对子对象数据成员初始化;
3、再执行派生类构造函数本身,对派生类数据成员初始化。
析构顺序:(与构造函数相反)
1、先执行派生类自己的析构函数,对派生类新增加的成员进行清理;
2、调用子对象的析构函数,对子对象进行清理;
3、调用基类的析构函数,对基类进行清理。
二、多态(接口复用)
同一接口指向不同形态
定义:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果(就是用基类的引用指向子类的对象)
特点:
三要素: 继承、重写和父类引用指向子类对象;