继承方式
class b : public a
class b : protected a
class b : private a
父类的私有属性,无论哪种继承方式,都无法访问
公共继承:父类的属性继承到子类时,是不变的
保护权限:都会变为保护权限
私有继承:都会变为私有权限
继承中的对象模型
class base
{
public:
int m_a;
protected:
int m_b;
private:
int m_c;
};
class son : public base
{
public:
int m_d;
}
cout<<sizeof(son)<<endl;
子类最终有十六个字节,父类中所有的非静态属性都会被继承,包括私有属性,只是无法访问
利用开发人员命令提示工具查看对象模型
跳转盘符
跳转文件路径 cd 具体路径下
查看别名
c1 /d1 reportSingleClassLayout类名 文件名
用于查看对象的具体内容
继承中构造和析构的顺序
当子类继承父类时,当创建子类对象,也会调用父类的构造函数
先调用父类的构造函数,后调用父类的析构函数
继承同名成员的处理方式
访问子类同名成员,直接访问即可
访问父类的同名成员,需要加作用域
//构建父类对象base,属性m_a = 100,func()
//构建子类对象son,属性m_a = 200,func()
son s;
cout<<s.m_a<<endl;
//访问子类中的属性
cout<<s.base::m_a<<endl;
//加入作用域,访问父类中的属性
s.func();
//调用子类函数
s.base::func();
//加入作用域,调用父类成员函数
如果子类中出现和父类同名的成员函数,子类的同名成员会隐藏掉父类中的所有同名成员函数
(即使父类的成员函数输入值与子类不同可以区分,也无法直接调用)
同名静态成员处理
通过对象来访问和非静态成员处理方式一致
//通过类名来访问
cout<<son::m_a<<endl;
cout<<son::base::m_a<<endl
//通过son类名来访问父类作用域下的属性
son::func();
son::base::func();
多继承语法
c++允许一个类继承多个类
语法:class 子类 :继承方法 父类1 ,继承方式 父类2
多继承可能会引发父类中有成名出现,需要加作用域区分
菱形继承
两个派生类继承同一个基类
又有某个类同时继承着两个派生类
这种继承被称为菱形继承,或者钻石继承
存在问题:
最终的类,继承了两份基类的属性,只需要一份即可
最终的类使用数据时,会出现二义性
利用虚继承解决
继承之前 加上关键字virtual变为虚继承
这样的父类称为虚基类
发生虚继承之后,相当于共享了基类的数据,这样就不会出现二义性,和数据重复
多态
多态分为两类:
静态多态:函数重载和运算符重载属于静态多态,复用函数名
动态多态:派生类和虚函数实现运行时多态
区别:
静态多态的函数地址早绑定 编译使其确定函数地址
动态多态的函数地址晚绑定 运行阶段确定函数地址
//构建animal父类,speak()函数
//构建cat子类,speak()函数
void dospeak(animal &animal)
//利用animal类型引用cat对象,c++允许父子类型转换
//在编译阶段就确定了函数的地址,所以输入的数据都会以animal数据类型处理
{
animal.speak();
}
void test1()
{
cat cat;
dospeak(cat);
}
virtual void speak();
//虚函数
//将基类的的speak()函数进行修改,实现地址晚绑定,根据运行时函数的输入,去调整speak()所在的数据类型
动态多态满足条件
1.存在继承关系
2.子类要重写父类中的虚函数
重写:函数返回值的类型 函数名 参数列表 完全相同
动态多态的使用
父类的指针或者引用执行子类对象
原理:当父类构建虚函数时,类内部储存了vfptr(虚函数表指针)指向vftable(虚函数表),内部储存着虚函数,当构建子类时,子类中会也存在vfptr,但是地址不同,内部储存着父类的虚函数,但是当子类重写虚函数时,内部会被替换为子类的虚函数
当父类的指针或者引用指向子类对象时,发生多态
animal & animal = cat;
//指针指向cat,会去调用子类中的虚函数
animal.speak();
多态练习
class abstractcalculator
{
public:
virtual int getresult()
{
return 0;
}
int m_num1;
int m_num2;
}
class add:public abstractcalculator
{
public:
virtual int getresult()
{
return m_num1+m_num2;
}
}
class sub:public abstractcalculator
{
public:
virtual int getresult()
{
return m_num1-m_num2;
}
}
void test()
{
abstractcalculator * abs = new add;
abs->m_num1 = 10;
abs->m_num2 = 20;
abs->getresult();
delete abs;
//本质是释放了堆区的数据,而不是删除指针
}
多态的写法有助于后期功能拓展,并且不需要修改源码