14 多态&虚函数
用基类的指针指向子类的对象,然后通过基类的指针调用实际子类的成员函数,虚函数使基类的指针具有了多态性,这是一种泛型技术,泛型技术就是试图用不变的代码来实现可变的算法。继承的时候虚函数也会被继承,尽管会被继承,但是还是要养成子类的同名函数也要写上virtual,这样显得直观。
在构造函数和析构函数调用虚函数的时候没有多态,因为子类还没初始化或子类已经被析构了,但是可以把析构函数定义为虚函数,但是不能是纯虚函数。父类的析构函数最好是虚函数(用父类指针指向new动态创建的对象,delete的时候虚函数的析构函数才会起作用),构造函数不需要不应该是虚函数,用不着去做类型识别。
通过继承,虚函数,指针或引用来实现,三个条件缺一不可。
#include<iostream>
using namespace std;
class animal
{
public:
animal(){cout << "animal构造!"<< endl;};
virtual ~animal(){cout <<"animal析构!"<<endl; };
virtual void shout(){cout << "animal is shouting!"<< endl;}
void sleep(){cout << "animal is sleeping!" << endl;};
void eat(){cout << "animal is eating!" << endl;};
};
class dog:public animal
{
public:
dog(){cout << "dog构造"<<endl;};
virtual ~dog(){cout << "dog析构" << endl;};
virtual void shout(){cout << "dog is shouting!" << endl;};
};
class sheep:public animal
{
public:
sheep(){cout << "sheep构造!" << endl;};
virtual ~sheep(){cout << "sheep析构" << endl;};
virtual void shout(){cout << "sheep is shouting!" << endl;};
};
int main()
{
animal a;
animal *d = new dog ;
animal *s = new sheep;
a.shout();
d->shout();
s->shout();
d->sleep();
s->eat();
delete d;
delete s;
return 0;
}
输出结果:
注意:new一定与delete配对使用,只有栈上的对象才会在程序中自动释放,堆上的对象(new)一定要delete。
14.1 函数的覆盖与隐藏
覆盖:派生类覆盖基类的虚函数,函数名和参数都相同
隐藏:派生类隐藏基类中同名函数(参数可不相同)
14.2 纯虚函数
virtual void eat()=0;
有纯虚函数的类称为抽象类
不允许创建抽象类的对象,但可以用抽象类的指针或引用去指向或引用子类的对象
14.3 开闭原则
普通成员函数:开辟好的类对扩展开放,对修改关闭
普通虚函数 : 暗示子类可以覆盖父类同名函数,子类自己实现
纯虚函数 : 如果要求子类必须自己实现,让父类变成抽象类
14.4 虚函数的本质
有虚函数的类每个对象有一个隐藏的指针成员指向本类的虚函数表。虚函数表里存着这个类的所有虚函数的地址,整个类只有一份 。
虚表指针直接是访问不到的,可以通过对象前4个字节找到它,可以破坏它
#include<iostream>
#include<cstring>
using namespace std;
class worker
{
public:
void virtual work()=0;
void virtual eat(){cout << "worker is eating!";};
void virtual sleep() {cout << "worker is sleeping!" << endl;};
};
class singer:public worker
{
public:
void virtual work(){cout << "singer is singing!" << endl;};
void virtual eat(){cout << "singer is eating!" << endl;};
void virtual sleep(){cout << "singer is sleeping" << endl;};
};
class writer:public worker
{
public:
virtual void work() {cout << "writer is writing!" << endl;};
virtual void eat(){cout << "writer is eating!" << endl;};
virtual void sleep(){cout << "writer is sleeping" << endl;};
};
int main()
{
worker *s = new singer;
worker *w = new writer;
s->work();
w->work();
memcpy(w,s,4); //把s所指的前4个字节复制到w所指向的前4个字节去,
//让w所指对象的虚表指针指向singer类虚函数表
w->work();
return 0;
}
输出结果:
关于虚函数与虚继承的相关细节可以参看:http://www.cnblogs.com/BeyondAnyTime/archive/2012/06/05/2537451.html