1.多态
虚函数,多态的条件,纯虚函数,纯虚函数的特点抽象类,typeinfo运算符,RTT1机制,运算符重载
通过基类指针只能访问派生类的成员变量,但是不能访问派生类的成员函数。 为了消除这种尴尬,让基类指针能够访问派生类的成员函数,C++ 增加了虚函数
(Virtual Function)。
虚函数: 在函数声明前面增加 virtual 关键字。
使用虚函数:
基类指针指向基类对象时就使用基类的成员(包括成员函数和成员变量),
指向派生类对象时就使用派生类的成员。
换句话说,基类指针可以按照基类的方式来做事,也可以按照派生类的方式来做事,它有多种形态,或者说有多种表现方式,我们将这种现象称为多态(Polymorphism)
C++提供多态的目的是:
可以通过基类指针对所有派生类(包括直接派生和间接派生)的成员变量和成员函数进行“全方位”的访问,尤其是成员函数。
派生类比较多,如果不使用多态,那么就需要定义多个指针变量,很容易造成混乱;
而有了多态,只需要一个指针变量 p 就可以调用所有派生类的虚函数。
A->B->C,A中声明虚函数
若C中没有display()函数,就去调用B中的display函数,如果B中没有display()函数就去A中调用display函数,如果A中没有那么就报错;
虚函数对于多态具有决定性的作用,有虚函数才能构成多态。
1) 只需要在虚函数的声明处加上 virtual 关键字,函数定义处可以加也可以不加。
2) 为了方便,你可以只将基类中的函数声明为虚函数,这样所有派生类中具有遮蔽(覆盖)关系的同名函数都将自动成为虚函数。
3) 当在基类中定义了虚函数时,如果派生类没有定义新的函数来遮蔽此函数,那么将使用基类的虚函数。
4) 只有派生类的虚函数遮蔽基类的虚函数(函数原型相同)才能构成多态(通过基类指针访问派生类函数)。例如基类虚函数的原型为virtual void func();,派生类虚函数的原型为virtual void func(int);,那么当基类指针 p 指向派生类对象时,语句p -> func(100);将会出错,而语句p -> func();将调用基类的函数。
5) 构造函数不能是虚函数。对于基类的构造函数,它仅仅是在派生类构造函数中被调用,这种机制不同于继承。也就是说,派生类不继承基类的构造函数,将构造函数声明为虚函数没有什么意义。
6) 析构函数可以声明为虚函数,而且有时候必须要声明为虚函数,如有的时候不调用声明为虚函数的析构函数就会发生内存泄露。
如
BaseA *p = new BaseA("zhou",20);
p->display();
p = new DerB("dong",11,90.5);
p->display();
基类Base A中有一个display(){cout<<m_name<<",year = "<<m_year<<",has no work"<<endl;};
派生类DerB中有一个disoplay(){cout<<m_name<<",age = "<<m_year<<",score is"<<m_socre<<endl;}
如果再基类Base A的display()前面没有加virtual声明虚函数,打印就是
zhou,20,has no work
2.纯虚函数
在C++中,可以将虚函数声明为纯虚函数,语法格式为:
virtual 返回值类型 函数名 (函数参数) = 0;
纯虚函数没有函数体,只有函数声明,在虚函数声明的结尾加上=0,表明此函数为纯虚函数。
最后的=0并不表示函数返回值为0,它只起形式上的作用,告诉编译系统“这是纯虚函数”。
包含纯虚函数的类称为抽象类(Abstract Class)。之所以说它抽象,是因为它无法实例化,也就是无法创建对象。原因很明显,纯虚函数没有函数体,不是完整的函数,无法调用,也无法为其分配内存空间。
抽象类通常是作为基类,让派生类去实现纯虚函数。派生类必须实现纯虚函数才能被实例化。
dong,11,has no work
如果再BaseA中display()前面加了virtual声明虚函数则打印是
zhou,year = 20,has no work
dong,age = 11,90.5
在基类中加virtual声明虚函数,那么基类指针(如BaseA *p = new BaseA("zhou",20);)就可以在指向基类对象(new BaseA("zhou",20);)的时候就可以访问基类的成员,在基类指针指向派生类的时候也可以访问派生类的成员
/
借助引用也可以实现多态:
当基类的引用指代基类对象时,调用的是基类的成员,而指代派生类对象时,调用的是派生类的成员。
///
多态的 条件:
a必须存在继承关系
b。继承中必须有同名的函数,并且也是遮蔽的关系
c存在基类指针。通过该指针调用虚函数