清华郑莉C++
虚函数
若你打算允许别人通过基类指针调用对象的析构函数(通过delete)就需要让基类的析构函数称为虚函数
否则执行delete的结果是不确定的
/*8_5.cpp 虚析构函数 */
#include<iostream>
using namespace std;
class Base{
public:
~Base();//不是虚函数
};
Base::~Base(){
cout<<"Base destructor"<<endl;
}
class Derived:public Base{
public:
Derived();
~Derived();//不是虚函数
private:
int *p;
};
Derived::Derived(){
p = new int(0);
}
Derived::~Derived(){
cout<<"Derived destructor"<<endl;
delete p;
}
void fun(Base *b){
delete b; //静态绑定,只会调用~Base
}
int main(){
Base *b = new Derived();
fun(b);//析构函数没有调用派生类中析构函数而是调用了基类中析构函数
return 0;
}
Base destructor
sd
针对8_5.cpp中;构函数没有调用派生类中析构函数而是调用了基类中析构函数
使用虚函数,使得派生类中与基类同名成员函数得到调用
虚函数表示意图
虚函数调用
虚函数指针vptr
虚函数表
纯虚函数:是一个在基类中声明的虚函数,它在该基类中没有定义
具体的操作内容,要求各派生类根据实际需要定义自己的版本,
声明格式:
virtual 函数类型(参数表) =0;
抽象类语法
带有纯虚函数的类称为抽象类:
class 类名{
virtual 类型 函数名(参数)=0;
其他类成员....
}
抽象类作用
将有关的数据和行为组织在一个继承层次结构中,保证派生类具有要求的行为。
对于暂时无法实现的函数,可声明为纯虚函数,留给派生类去实现
注意:抽象类只能作为基类使用、不定定义抽象类的对象
虚函数:
不设置为虚函数,派生类对象调用与基类同名成员函数,只能调用基类中成员函数
虚函数,有利于灵活地运行派生类及扩展多态形式
/*8_6.cpp 、
*/
#include<iostream>
using namespace std;
//抽象类:带有纯虚函数的类称为抽象类
//且抽象类只能作为基类使用,不能定义抽象类的对象
class Base1{
public:
virtual void display()const = 0;//纯虚函数
// void display()const = 0;//
};
void Base1::display() const{
cout<<"Base1::display()"<<endl;
}
//派生类
class Base2:public Base1{
public:
virtual void display() const;//覆盖基类虚函数
};
void Base2::display() const{
cout<<"Base2::display()"<<endl;
}
class Derived:public Base2{
public:
virtual void display() const;//覆盖基类的虚函数
};
void Derived::display() const{
cout<<"Derived::display()"<<endl;
}
//void fun(Base2 *ptr){ //结果一样。?
void fun(Base1 *ptr){
ptr->display();
}
int main(){
//抽象类只能作为基类使用,不能定义抽象类的对象
// Base1 base1;//erro
Base2 base2;
Derived derived;
// fun(&base1);8
fun(&base2);
fun(&derived);
return 0;
}
Base2::display()
Derived::display()
override
多态行为的基础:基类声明虚函数,派生类声明一个函数覆盖该虚函数
覆盖要求:函数签名(signature)完全一致
函数签名:函数名 参数列表 const
/*8_7.cpp*/
#include<iostream>
using namespace std;
class Base{
public:
virtual void f1(int) const;
virtual ~Base() {}
};
void Base::f1(int) const{
cout<<"Base f1"<<endl;
}
class Derived:public Base{
public:
void f1(int);
~Derived(){
}
};
void Derived::f1(int){
cout<<"Derived f1"<<endl;
}
int main(){
Base *b;
b = new Base;
b->f1(1);//Base f1
b = new Derived;
b->f1(1);//Base f1 没有调用派生中成员函数,基类中成员函数为虚函数
return 0;
}
Base f1
Base f1
C++11引入显示函数覆盖,在编译期间而非运行时期间捕获此类错误;
在虚函数显示重载中运用,编译器会检查基类是否存在一虚函数,与派生类中带有声明override的虚函数,有相同函数签名(signature);若存在,则会回报错误 ;
/*8_7_1.cpp*/
struct Base1 final{
};
struct Derived :Base1{ //编译错误:Base1为final,不允许被继承
};
struct Base2{
virtual void f() final;
};
struct Derived2:Base2{
void f();//编译错误:Base2::f 为final,不允许被覆盖
};