【C++】继承和多态
一、继承
继承是使代码复用的一种机制。(本质)
单继承:一个派生类一个基类派生。
多继承:一个派生类有两个人或者多个基类。(如:马与驴杂交所生的骡子就有两个基类,骡子既继承了马的一些特征,也继承了驴的一些特征)
派生类
构造派生类包括:
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)类和类的关系:
1、组合关系;has_a关系 a part of
2、继承关系;is_a关系 a kind of(私有继承不是is_a的关系,是has_a的关系)
protetced/private继承是一个实现继承,基类的部分成员并非完全成为子类接口的一部分,是 has-a 的关系原则。晚餐有香蕉,香蕉不是晚餐
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
①同作用域;
②同名;
③参数列表不同。
2、隐藏 overhide
①作用域不同 继承关系
隐藏了基类中所有同名函数。(隐藏:继承关系、同名)
3、覆盖 override
派生类中同名同参的虚函数覆盖基类中同名同参的虚函数
①继承;
②虚函数;
③同名同参。
(3)基类和派生类指针或者引用的相互指向或者引用
允许基类指针指向或者引用派生类对象;
不允许派生类指针指向或者引用基类对象;
(4)派生类的构造和析构顺序(先构造后析构)
构造顺序:
1、调用基类构造函数,对基类数据成员初始化;
2、调用子对象构造函数,对子对象数据成员初始化;
3、再执行派生类构造函数本身,对派生类数据成员初始化。
析构顺序:(与构造函数相反)
1、先执行派生类自己的析构函数,对派生类新增加的成员进行清理;
2、调用子对象的析构函数,对子对象进行清理;
3、调用基类的析构函数,对基类进行清理。
二、多态(接口复用)
同一接口指向不同形态
定义:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果(就是用基类的引用指向子类的对象)
特点:
①提高程序的可复用性;(不必为每一个派生类编写功能调用,只需对抽象基类进行处理)
②提高可扩充性和可维护性
三要素: 继承、重写和父类引用指向子类对象;
父类引用指向不同的子类对象时,调用相同的方法呈现出不同的行为就是类多态的特性。