一.重写与重载
class Parent { public: virtual void func() { cout<<" void func()"<<endl; } virtual void func(int i) { cout<<" void func(int i)"<<endl; } virtual void func(int i,int j) { cout<<" void func(int i,int j)"<<endl; } }; class Child:public Parent { public: virtual void func(int a,int b) { cout<<" void func(int a,int b)"<<endl; } virtual void func(int i,int j,int k) { cout<<" void func(int i,int j,int k)"<<endl; } };
函数重载:
(1)必须在同一类中,也就是在同一个作用域中。
(2)
子类无法重载父类的函数,父类同名函数被覆盖
如: c.func();//错误,编译不过
(3)重载是在编译期间根据参数类型和个数决定调用函数的
函数重写:
(1) 必须发生在父类与子类之间
(2)
并且父类与子类中的函数必须有完全相同的原型。
(3)
使用 virtual 声明之后能顾产生多态
(4)
多态是在运行期间根据具体对象的类型决定调用函数的
对比:
一个是在编译期间决定的,一个是在运行期间决定的,所以重载的效率还是比重写的效率高。
二. 对虚函数的理解
C++中多态的实现原理
(1)
当类中声明虚函数时,编译器会在类中生成一个虚函数表
(2)
虚函数表是一个存储类成员函数指针的数据结构
(3)
虚函数表是由编译器自动生成与维护的
(4) virtual 成员函数会被编译器放入虚函数表中
(5)
存在虚函数时,每个对象中都有一个指向虚函数表的指针。
void run(Parent* p) { p->func(1,2); }
通过虚函数表指针VPTR调用重写函数是在程序运行时进行的,因此需要通过寻址操作才能确 定真正的应该调用的函数。而普通成员函数是在编译时就确定了调用的函数。在效率上,虚函数
的效率要低的多。
注意:
处于效率的考虑,没有必要把所有的成员函数都声明为虚函数。
对象中VPTR指针什么时候被初始化的?
(1)
对象在创建的时候由编译器对VPTR指针进行初始化,
(2)
只有当对象的构造完全结束后VPTR的指向才最终确定
(3)
父类对象的VPTR指向父类虚函数表
(4)
子类对象的VPTR指向子类虚函数表
class Parent { public: Parent() { this->func(); } virtual void func() { cout<<"virtual void Parent::func()"<<endl; } }; class Child:public Parent { public: Child() { func(); } void func() { cout<<"void Child::func()"<<endl; } }; int main() { Child p; p.func(); return 0; }
结论: 构造函数中调用虚函数无法实现多态
三. 纯虚函数
面向对象的抽象类
(1) 抽象类可用于表示现实世界中的抽象概念
(2) 抽象类是一种只能定义类型,而不能产生对象的类
(3) 抽象类只能被继承并重写相关函数
(4) 抽象类的直接特征是纯虚函数
说明: 纯虚函数只声明函数原型,不定义函数体的虚函数。
抽象类与纯虚函数
(1) 抽象类不能用于定义对象
(2) 抽象类只能用于定义指针和引用
(3) 抽象中的纯虚函数必须被子类重写
class Shape { public: virtual double area()=0; };
area是纯虚函数, =0 告诉编译器这个函数故意只声明不定义。
class Shape { public: virtual double area() = 0; }; class Rectangle : public Shape { double m_a; double m_b; public: Rectangle(double a, double b) { m_a = a; m_b = b; } double area() { return m_a * m_b; } }; class Circle : public Shape { double m_r; public: Circle(double r) { m_r = r; } double area() { return 3.14 * m_r * m_r; } }; void area(Shape* s) { cout<<s->area()<<endl; } int main(int argc, char *argv[]) { Rectangle rect(2, 3); Circle circle(4); area(&rect); area(&circle); return 0; }
小结:
(1) 函数重载与函数重写不同
(2) 多态是通过虚函数实现的
(3) 虚函数在效率上会有影响
(4) 抽象类是通过纯虚函数实现的。