面向对象
面向对象的三大特征:封装,继承,多态,这三种机制能有效提升程序的可读性、可扩充性和可重用性。
多态
指的同一个名字的事物可以完成不同的功能。多态可以分为编译时的多态和运行时的多态。
编译多态:函数重载,运算符重载,对重载函数的调用,在编译的时候能根据实参确定应该调用哪个函数,这叫做编译时的多态。
运行多态:继承,虚函数
可以这么理解:运行时的多态就是基类的指针指向派生类。
虚函数
如果基类的指针指向派生类,那么我们应该能使用派生类的成员变量和成员函数,但是现实情况是不能使用派生类的成员函数。
比如一个Teacher类继承了一个People类,都有成员函数occupation(),People是打印无业游民,Teacher打印是有老师岗位,这时候我们new个小李是个老师,当基类的指针指向派生类并调用成员函数时候,应该打印小李是有工作的,但是实际上却是无业游民。这就是尴尬的地方了。。。
Class People{
public:
People(char *name,int age);
void occupation();
protected:
char *name;
int age;
};
People::People(char *name,int age):m_name(name),
m_age(age){)
void People::occupation(){
cout<<m_name<<"今年"<<m_age<<"岁,是个无业游民。"<<endl;
}
//派生类Teacher
class Teacher: public People{
public:
Teacher(char *name, int age, int salary);
void occupation();
private:
int m_salary;
};
Teacher::Teacher(char *name, int age, int salary): People(name, age), m_salary(salary){}
void Teacher::occupation(){
cout<<m_name<<"今年"<<m_age<<"岁了,是一名教师,每月有"<<m_salary<<"元的收入。"<<endl;
}
int main(){
People *p = new People("小王", 25);
p -> occupation();
p = new Teacher("小李", 26, 10000);
p -> occupation();
return 0;
}
所以为了消除这种尴尬,C++增加了虚函数。使用虚函数也很简单,只需要在函数声明前加上virtual关键字,将基类的这个成员函数声明为虚函数就可以了。
virtual void occupation();
这样就可以通过指针调用派生类的成员函数了。
有了虚函数,基类指针指向基类对象时就使用基类的成员(包括成员函数和成员变量),指向派生类对象时就使用派生类的成员。换句话说,基类指针可以按照基类的方式来做事,也可以按照派生类的方式来做事,它有多种形态,或者说有多种表现方式,我们将这种现象称为多态。
也可以说一条同样的指令却执行不同的操作,这就是多态。多态是面向对象编程的主要特征之一,C++中的虚函数唯一的作用就是构成多态。
虚函数的注意事项
1.只需要在函数声明前加virtual关键字,函数定义处可加可不加
2.只把基类的函数声明为虚函数即可,这样派生类有遮蔽关系的同名函数都自动成为虚函数
3.当基类定义了虚函数,如果派生类没有定义新的函数来遮蔽此函数,那么将使用基类的虚函数
4.只有派生类的虚函数覆盖基类虚函数,才能构成多态,通过基类指针访问派生类的成员函数。函数原型要相同,参数列表不能不同。
5.构造函数不能是虚函数。
6.析构函数可以是虚函数,而且有时候必须声明为虚函数
构成多态的条件
1.必须存在继承关系
2.继承关系中必须有同名的虚函数,并且是覆盖关系(函数原型相同)
3.存在基类指针,通过该指针调用虚函数
什么时候用虚函数
成员函数所在的类是否作为基类,然后看成员函数在类继承以后是否实现新的功能。如果明确要改功能,就要声明为虚函数,不需要的话就不要声明为虚函数。