1)C++利用虚函数来实现多态。
程序执行时的多态性通过虚函数体现,实现运行时多态性的机制称爲动态绑定;与编译时的多态性(通过函数重载、运算符重载体现,称爲静态绑定)相对应。
在成员函数的声明前加上virtual修饰,派生类可以不加virtual修饰,则声明之为虚函数。在派生类中可以重新定义从基类继承下来的虚函数。下面是一个例子,Rectangle是Shape的派生类,在类Rectangle中对Shape中的虚函数Draw()进行了重新定义:
class Shape { public: virtual void Draw() { } }; class Rectangle : public Shape { public: virtual void Draw() { } };
类Rectangle中的Draw()函数前面的virtual可不加,那麽它就不再可以被它的继承类重新定义。
虚函数的调用
要想调用一个在派生类中重定义的函数,必须使用多态调用,它必须使用指针来实现。下面是一个典型的例子:
void fun1(Shape s) { s.Draw(); } //非多态 void fun2(Shape &s) { s.Draw(); } //多态 void fun3(Shape *s) { s->Draw(); } //多态 int main() { Rectangle rr; fun1(rr); //调用类Shape的Draw() fun2(rr); //调用类Rectangle的Draw() fun3(&rr); //调用类Rectangle的Draw() }
只有使用指针和引用调用时,才能进行多态调用。
2)技巧:虚函数的调用地址只看对象声明时的类名(看后面),普通函数的调用地址看对象定义时的类名(看前面)。
所以构造函数不能是虚函数,而析构函数最好是虚函数。
如下:
#include<iostream> using namespace std; class A { public: void foo() { printf("1 "); } virtual void fun() { printf("2 "); } }; class B : public A { public: void foo() { printf("3 "); } void fun() { printf("4 "); } }; int main(void) { A a; B b; A *p = &a; p->foo(); //1 p->fun(); //2 p = &b; p->foo(); //1,普通函数看前面,调用的就是A类的方法。 p->fun(); //4,虚函数看后面,调用的是 B类的方法。 return 0; }
B *ptr = (B *)&a; ptr->foo(); //3,普通函数看前面,所以调用的是 B类的方法。 ptr->fun(); //2,虚函数看后面,所以调用的是A类的方法。
原理可以看这篇文章:
C++虚函数与虚函数表
3)纯虚函数
纯虚函数是在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。在基类中实现纯虚函数的方法是在函数原型后加“=0”
virtual void funtion()=0
类似于java里的interface,派生类必须要实现它。
4)虚继承
参考:c++ 虚继承详解 http://blog.163.com/redhumor@126/blog/static/19554784201131174216260/