1、利用多态调用不同方法
//.h
Class Base{
public:
virtual ~Base() {};
virtual funcA();
funcB();
funcC();
}
Class Child: public Base{ //默认为private 继承
public:
virtual funcA();
funcB();
}
//.cpp
Base * ptr1 = new Base();
Base * ptr2 = new Child();
//1、验证虚函数的作用:根据指针/引用指向的对象类型选择方法
ptr1->funcA(); // 调用Base::funcA();
ptr2->funcA(); // 调用Child::funcA();
//2、验证非虚函数作用:根据指针/引用类型选择方法
ptr1->funcB(); // 调用Base::funcA();
ptr2->funcB(); // 调用Base::funcA(); 此时可能调用非目标函数
//3、验证虚析构函数作用:正确执行派生类与基类析构顺序
(若析构函数为虚函数)delete ptr2; // 先析构child 后析构 base
//调用相应对象类型的析构函数
(若析构函数不为虚函数)delete ptr2; // 只析构base
//只调用对应于指针类型的析构函数
注:
应用场景:基类指针数组同时管理多个对象,指针可以根据对象类型调用不同方法。
2、作用域指定方法
//方法实现.cpp
Child::funcA(){
if(...)
Base::funcA(); //通过作用域指定调用基类方法
else
funcC(); //因派生类未重写该方法,因此不必使用作用域解析运算符
//同时不需要 this->funcC(),因为继承了接口和实现;
...;
}
两种方式去调用基类被覆盖的方法(均使用作用域解析运算符:: ) 详细介绍。
1: 直接在派生类中调用被覆盖的基类方法,如 Base::funcA() ;
2: 使用派生类对象调用被覆盖的基类方法,如 child.Base::funcA();
3、虚函数原理
1、每个类对象增加一个隐藏成员变量:为指向虚函数地址数组的指针。此地址数组称为虚函数表。
2、编译器为每个类增加一个虚函数地址表(数组)。因为,方法是类所有对象共有的,因此一个类仅需要一个虚函数表。
3、每次虚函数调用,需要到表中查找地址,因此消耗时间。
注:
1、构造函数不能为虚函数:子类基类构造函数间为调用关系,非继承关系,虚函数用于继承。因此构造函数不为虚函数。
2、友元函数不能为虚函数:友元函数不是类成员函数,因此不能为虚函数。
总结
1、通过虚函数利用基类指针调用子类方法。
2、通过作用域解析运算符制定调用基类方法。
3、将基类析构函数定义为虚函数,保证正确析构顺序。
4、调用未重载基类函数,不需要作用域解析运算符。
5、虚函数原理为增加虚表虚指针。
6、构造函数、友元函数不能为虚函数。