概述
继承的本质:类的拷贝
B类继承A类,称A为基类/父类,称B类为派生类/子类
派生类格式: class 派生类名:派生方式 基类名{};
派生方式:
- public: 直接拷贝到子类,即子类对象在类外能访问父类的public;子类的成员函数能访问父类的public和protect
- private: public和protect变private再拷贝到子类,即子类对象在类外不能访问拷贝过来的成员;子类的成员函数能访问父类的public和protect
- protect: public变protect再拷贝到子类,即子类对象在类外不能访问拷贝过来的成员;子类的成员函数能访问父类public和protect
继承中的构造和析构
父类/基类:
class Base
{
public:
Base(int age, string name) //有参构造
{
this->age=age;
this->name=name;
}
int age;
string name;
}
子类/派生类:
class Son : public Base
{
public:
//先构造父类(用初始化列表形式)
Son(int age, string name, int id):Base(age, name)
{
this->id=id;
}
}
析构则是先析构子类
不会继承的函数:构造函数,析构函数,operator=函数
继承中的同名问题
如果父类和子类中有同名的(静态)成员变量或函数,父类的成员会被隐藏,访问的是子类的。
多继承
概念:一个类继承多个类
class C: public A, public B
{
};
若A,B中有同名的成员,要声明作用域
若C中有与A,B同名的成员,A,B的成员被隐藏
菱形继承和虚继承
动物
羊 驼
羊驼
羊,驼类继承动物类
羊驼类继承羊,驼类
这称为菱形继承
此时定义一个羊驼类对象,此对象会产生两份动物类成员(羊类和驼类同时继承),若要羊驼类只继承一份,要在羊类和驼类继承动物类时加关键字virtual,如class sheep:virtual public animal{};,这也称为虚继承
多态
概念:一种接口多种形态
静态多态:编译时,地址早绑定(静态联编)
foo(),foo(int)
动态多态:运行时,才确定需要调用的地址(动态联编)
注:如果两个类发生继承,那么编译器会自动转换类型,如B继承A,那么形参(A &p),它的实参既可以用A类对象,也可以用B类对象。
发生多态的条件:
- 父类必须有虚函数
- 必须发生继承
- 子类重写虚函数(函数内容可以不同)
- 父类的指针(形参)指向子类的对象
抽象类和纯虚函数
纯虚函数:虚函数=0;例如virtual int foo(int a,int b)=0;实质是将虚函数表的接口地址置为NULL;
抽象类:有纯虚函数的类;不能实例化对象。
子类继承了抽象类:
若未重写纯虚函数,那么子类也是抽象类
若重写了纯虚函数,那么子类不为抽象类
虚析构
作用:在调用基类的析构函数之前,先调用子类的析构函数
纯虚析构
虚析构=0;(抽象类)
重写/重载/重定义
重载:同一作用域,函数名相同,形参不同
重定义:有继承,子类重定义同名函数成员
重写:有继承,父类有虚函数(除函数内容可不同,其余要相同)