理解多态
2016-03-22 13:18
295 查看
多态
多态即多种状态
多态又分为静态多态和动态多态,静多态即重载,动态多态即通过继承将基类的虚函数重写
虚函数
B::show()
若在基类的同名函数前加virtual变为虚函数
输出结果:D::show()
B::show()
--->覆盖:子类重新定义了基类的虚函数并且他们的函数名参数列表和返回值均相同(协变除外)
多态:
用基类的指针指向基类的对象,调用虚方法(virtual)
1.派生类重写基类的虚方法实现多态,要求函数名、参数、返回值完全相同(协变除外)。
ps:协变即在基类的方法中返回基类的指针,子类返回子类的指针,即返回值不同
2.若在基类中是虚函数,则在子类中也是虚函数(保持虚函数特性)
3.只有类的成员才能定义为虚方法
4.静态成员函数(默认成员列表中无this)不能定义为virtual
5.在类外实现类的成员函数时,只能在类内声明时加virtual,在类外定义时不加virtual
6.构造函数不能定义为虚函数,operator=最好不要定义为虚函数
7.不要在构造函数和析构函数中调用虚函数
8.最好把基类的析构函数写为虚函数
D()
~B()
不会调用子类的析构函数
子类调用析构函数时会自动调用基类的析构函数,故在基类的析构函数前加virtual时,则析构时先析构子类再析构基类
定义为virtual的函数的地址均依次保存在__vfptr的指向表内
若去掉virtual,输出:4
B::fun2
D::fun3
D::fun4
____________
B::fun1
B::fun2
多态即基类的虚函数被子类重写,其实是把属于子类的虚函数表里基类的虚函数地址改为子类的,这样,在创建指向基类的指针指向子类时即调用子类函数
带有纯虚函数的类称为抽象类或者接口类。抽象类不能实例化对象,若子类继承抽象类而没有实现虚函数定义,则此子类也是抽象类不能实例化对象,只有实现了纯虚函数才能实例化对象。
多态即多种状态
多态又分为静态多态和动态多态,静多态即重载,动态多态即通过继承将基类的虚函数重写
虚函数
class B { public: void show()// { cout << "B::show" << endl; } }; class D :public B { public: void show() { cout << "D::show" << endl; } }; void fun(B *pb)//只有传入基类指针才能指向函数 { pb->show(); } int main() { D d; B b; fun(&d); fun(&b); getchar(); return 0; }输出结果:B::show()
B::show()
若在基类的同名函数前加virtual变为虚函数
输出结果:D::show()
B::show()
--->覆盖:子类重新定义了基类的虚函数并且他们的函数名参数列表和返回值均相同(协变除外)
多态:
用基类的指针指向基类的对象,调用虚方法(virtual)
1.派生类重写基类的虚方法实现多态,要求函数名、参数、返回值完全相同(协变除外)。
ps:协变即在基类的方法中返回基类的指针,子类返回子类的指针,即返回值不同
2.若在基类中是虚函数,则在子类中也是虚函数(保持虚函数特性)
3.只有类的成员才能定义为虚方法
4.静态成员函数(默认成员列表中无this)不能定义为virtual
5.在类外实现类的成员函数时,只能在类内声明时加virtual,在类外定义时不加virtual
6.构造函数不能定义为虚函数,operator=最好不要定义为虚函数
7.不要在构造函数和析构函数中调用虚函数
8.最好把基类的析构函数写为虚函数
class B { public: B() { cout << "B()" << endl; } ~B() { cout << "~B()" << endl; } }; class D :public B { public: D() { cout << "D()" << endl; } ~D() { cout << "~D()" << endl; } }; int main() { //D d; B *pb = new D; delete pb; system( "pause"); return 0; }输出:B()
D()
~B()
不会调用子类的析构函数
子类调用析构函数时会自动调用基类的析构函数,故在基类的析构函数前加virtual时,则析构时先析构子类再析构基类
定义为virtual的函数的地址均依次保存在__vfptr的指向表内
class B { public: virtual void show()// { } }; class D :public B { public: void show() { } int _d; }; int main() { cout << sizeof(D ) << endl; getchar(); return 0; }输出:8
若去掉virtual,输出:4
typedef void (*PFUN)(); void PrintVT(int p) { PFUN pfun = NULL ; int* ptr = (int *)p; int i = 0; while (ptr[i]) { pfun = ( PFUN)ptr[i]; pfun(); i++; } } class B { public: virtual void fun1() { cout << "B::fun1" << endl; } virtual void fun2() { cout << "B::fun2" << endl; } private: int _a; }; class D :public B { public: virtual void fun1()//覆盖 { cout << "D::fun1" << endl; } virtual void fun3() { cout << "D::fun3" << endl; } virtual void fun4() { cout << "D::fun4" << endl; } private: int _b; }; int main() { D d; PrintVT(*( int*)&d); cout << "_________" << endl; B b; PrintVT(*( int*)&b); getchar(); return 0; }输出:D::fun1//子类fun1覆盖了基类的fun1,虚函数里的地址覆盖
B::fun2
D::fun3
D::fun4
____________
B::fun1
B::fun2
多态即基类的虚函数被子类重写,其实是把属于子类的虚函数表里基类的虚函数地址改为子类的,这样,在创建指向基类的指针指向子类时即调用子类函数
void fun(B * pb) { pb->fun1(); } fun(&d);//调用子类里的函数纯虚函数
class Person { virtual void Display() = 0; };基类中有一个虚函数,在后面有“=0”的形式,且不实现,说明为虚函数,一般它的实现留给该基类的派生类。
带有纯虚函数的类称为抽象类或者接口类。抽象类不能实例化对象,若子类继承抽象类而没有实现虚函数定义,则此子类也是抽象类不能实例化对象,只有实现了纯虚函数才能实例化对象。
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- 关于指针的一些事情
- c++ primer 第五版 笔记前言
- share_ptr的几个注意点
- C#与.net高级编程 C#的多态介绍
- C#中面向对象编程机制之多态学习笔记
- Lua中调用C++函数示例
- Lua教程(一):在C++中嵌入Lua脚本
- Lua教程(二):C++和Lua相互传递数据示例
- C#中的多态深入理解
- C#中多态、重载、重写区别分析
- 设计引导--一个鸭子游戏引发的设计理念(多态,继承,抽象,接口,策略者模式)
- C++联合体转换成C#结构的实现方法
- C++高级程序员成长之路
- C++编写简单的打靶游戏
- C++ 自定义控件的移植问题
- C++变位词问题分析
- C/C++数据对齐详细解析
- C++基于栈实现铁轨问题
- C++中引用的使用总结