1.虚函数继承与非虚函数继承
如果基类是非虚函数,在继承类中重写该函数时,我想应该不属于继承,而是继承类自己定义的接口。
#include<iostream>
#include <string>
#include <vector>
using namespace std;
class Base{
public:
void test(){ cout << "base test" << endl; }
};
class Derived:public Base{
public:
void test(){ cout << "derived test" << endl; }
};
int main()
{
Base *a = new Derived();
a->test();
Derived b;
b.test();
return 0;
}
输出:
base test
derived test
如输出所示,非虚函数没有了动态绑定功能。
注意:如果不是虚函数,就不能在继承类同名函数后面加上override关键字。
因为派生类对象中含有与基类对应的组成部分(关系是is-a),所以能将派生类对象当做基类对象来使用,也能将基类的指针或引用绑定到派生类对象中的基类成分上。
2.静态成员的继承
如果基类定义了一个静态成员,则在整个继承体系中只存在该成员的唯一定义。静态成员遵循访问控制原则,如果基类的静态成员是private的,则派生类无权访问它。如果某静态成员是可访问的,则我们既可以通过基类base::staticData也可以通过继承类derived::staticData访问。
3.派生类和基类的声明
派生类的声明如下:
class Derived; //正确
class Derived :public Base; //错误
基类只声明不定义不能被继承:派生类包含并使用从基类继承而来的成员,因此继承前必须知道基类是什么。
一个类不能派生它本身。
4.防止被继承的方法
可以在类定义时,在类名后面跟上final关键字,就可以阻止该类作为基类。
class Base final{
public:
virtual void test(){ cout << "base test" << endl; }
protected:
int idata;
};
Base不能作为基类。
class Base{
public:
virtual void test(){ cout << "base test" << endl; }
protected:
int idata;
};
class Derived final:public Base{
public:
Derived(){ idata = 0; }
void test() override { cout << "derived test" << endl; }
};
Derived不能作为基类。
5.对象切割
当我们用一个派生类对象为一个基类对象初始化或赋值时,只有该派生类对象中的基类部分被拷贝、移动或赋值,他的派生类部分将被忽略掉。
6.派生类中的虚函数
一旦某个函数被声明成虚函数,则在所有派生类中它都是虚函数。
派生类中虚函数的返回类型必须与基类函数匹配。但是当类的虚函数返回类型是类本身的指针或引用时,可以不一样。不过这要求从继承类到基类的类型转换是可以访问的。
前面说过final关键字可以阻止成为基类,也可以阻止函数被继承类覆盖(该函数必须是virtual才能使用final)。
class Base{
public:
virtual void test() final{ cout << "base test" << endl; }
protected:
int idata;
};
class Derived final:public Base{
public:
Derived(){ idata = 0; }
void test() { cout << "derived test" << endl; } //错误,不能覆盖
};
7.回避虚函数的动态绑定
有些时候,我们希望对虚函数调用不进行动态绑定,则可以使用作用域运算符。
#include<iostream>
#include <string>
#include <vector>
using namespace std;
class Base{
public:
virtual void test(){ cout << "base test" << endl; }
protected:
int idata;
};
class Derived final:public Base{
public:
Derived(){ idata = 0; }
void test() { cout << "derived test" << endl; } //错误,不能覆盖
};
int main()
{
Base *a = new Derived();
a->Base::test();
Derived b;
b.test();
return 0;
}
8.纯虚函数
我们在函数体的位置书写=0可以将一个虚函数说明为纯虚函数。其中=0只能出现在类内部的虚函数声明语句处。
注意:一个纯虚函数无需定义,我们也可以为纯虚函数提供定义,但是函数体必须定义在类的外部。