虚继承:通过关键字virtual修该一个基类的声明,可以将它指定为被虚拟派生
虚函数:virtual 返回值类型 虚函数名(形参表){……}
纯虚函数:一个虚函数不需要或者不能写出任何实现时,被定义为纯虚函数
例如:virtual void f()=0;
抽象类:带有纯虚函数的类,不能被实例化,与接口的区别:
1)抽象类是一类事物的高度聚合,那么对于继承抽象类的子类相对于抽象类来说,属于“是”的关系;而接口是定义行为的规范,因此对于实现接口的子类相对于接口来说,是“行为需要按照接口来完成”。
2)抽象类在定义类型方法的时候,可以给出方法的实现部分,也可以不给出;而对于接口来说,其中所定义的方法都不能给出实现部分。
3)继承类对于抽象类所定义的抽象方法,可以不用重写,也就是说,可以延伸抽象类的方法;而对于接口类所定义的方法或者属性来说,在继承类中必须要给出相应的方法和属性实现。
4)在抽象类中,新增的一个方法的话,继承类中可以不用作任何处理;而对于接口,则要修改继承,提供新定义的方法。
虚基类的声明:class 派生类名:virtual 继承方式 基类名{……};
虚基类举例如下:
#include<iostream>
using namespace std;
class B0
{
public:
B0(){
cout<<"构造"<<endl;
}
~B0(){
cout<<"析构"<<endl;
}
B0(int n){ nv=n;}
int nv;
void fun()const{
cout<<"Member of B0"<<endl;
}
};
class B1:virtual public B0
{
public:
B1(int a):B0(a){}
int nv1;
};
class B2:virtual public B0
{
public:
B2(int a):B0(a){}
int nv2;
};
class D1:public B1,public B2
{
public:
D1(int a):B0(a),B1(a),B2(a){}
int nvd;
void fund()const{
cout<<"Member of D1"<<endl;
}
};
int main()
{
D1 d1(1);
d1.nv=2;
d1.fun();
return 0;
}
运行结果:
Member of B0
析构
也可以解决同名成员惟一标识的问题
原理:当某类的部分或者全部直接基类是从另一个共同基类派生而来时,这些直接基类中从上一级共同基类继承来的成员就拥有相同的名称。在派生类的对象中,这些同名的数据成员在内存中同时拥有多个拷贝,同一个函数名会有多个映射。首先我没可以用作用域分辨符(::)来惟一分别访问他们,也可以将共同的基类设置为虚基类,这时从不同的路径继承过来的同名数据成员在内存中就只有一个拷贝,同一个函数名也只有一个映射。
补充:
多继承中常考知识点举例:
#include<iostream>
using namespace std;
class A{
public:
A(){cout<<"construction"<<endl;}
virtual ~A(){cout<<"disconstruction"<<endl;}
};
class B:public A{
};
class C:public A{
};
class D:public B,public C{
};
int main()
{
D d;
return 0;
}
运行结果:
construction
construction
disconstruction
disconstruction