c++ 34 虚函数与多态一
2014-11-24 21:47
162 查看
其中,虚函数 动态多态,其他静态多态
#include <iostream> using namespace std; class Base { public: virtual void Fun1() { cout<<"Base::Fun1.."<<endl; } virtual void Fun2() { cout<<"Bae::Fun2.."<<endl; } void Fun3() { cout<<"Base::Fun3"<<endl; } }; class Derived:public Base { public: virtual void Fun1()//即使不加virtual 也是虚函数 { cout<<"Derived::Fun1.."<<endl; } virtual void Fun2()//即使不加virtual 也是虚函数 { cout<<"Derived::Fun2.."<<endl; } void Fun3() { cout<<"Derived::Fun3"<<endl; } }; int main(void) { Base* p; Derived d; p=&d; p->Fun1(); p->Fun2(); p->Fun3(); return 0; }
打印结果
基类指针指向派生类对象。调用虚函数会调用实际指向的虚函数,而如果是普通的函数,就会根据指针的类型,来调用相应类的成员函数。
Fun1 是虚函数,基类指针指向派生类对象,调用的是派生类对象的虚函数。
是在运行使其确定的。
析构函数 怎么调用的?
#include <iostream> using namespace std; class Base { public: virtual void Fun1() { cout<<"Base::Fun1.."<<endl; } virtual void Fun2() { cout<<"Bae::Fun2.."<<endl; } void Fun3() { cout<<"Base::Fun3"<<endl; } ~Base() { cout<<"~Base.."<<endl; } Base() { cout<<"Base.."<<endl; } }; class Derived:public Base { public: virtual void Fun1()//即使不加virtual 也是虚函数 { cout<<"Derived::Fun1.."<<endl; } virtual void Fun2()//即使不加virtual 也是虚函数 { cout<<"Derived::Fun2.."<<endl; } void Fun3() { cout<<"Derived::Fun3"<<endl; } ~Derived() { cout<<"~Derived..."<<endl; } Derived() { cout<<"Derived..."<<endl; } }; int main(void) { Base* p; p=new Derived;//基类指针指向派生类对象 p->Fun1(); delete p;//如果析构函数不是虚的。 根据p的指针类型来确定 return 0; }
#include <iostream> using namespace std; class Base { public: virtual void Fun1() { cout<<"Base::Fun1.."<<endl; } virtual void Fun2() { cout<<"Bae::Fun2.."<<endl; } void Fun3() { cout<<"Base::Fun3"<<endl; } virtual ~Base()//如果一个类要作为多态基类,要将析构函数,否则就存在内存泄漏,如果没有被其他类继承,就没有必要 { cout<<"~Base.."<<endl; } Base() { cout<<"Base.."<<endl; } }; class Derived:public Base { public: virtual void Fun1()//即使不加virtual 也是虚函数 { cout<<"Derived::Fun1.."<<endl; } virtual void Fun2()//即使不加virtual 也是虚函数 { cout<<"Derived::Fun2.."<<endl; } void Fun3() { cout<<"Derived::Fun3"<<endl; } ~Derived()//这里不加也是虚函数 base 有加 { cout<<"~Derived..."<<endl; } Derived() { cout<<"Derived..."<<endl; } }; int main(void) { Base* p; p=new Derived;//基类指针指向派生类对象 p->Fun1(); delete p;//如果析构函数不是虚的。 根据p的指针类型来确定 return 0; }
派生类的析构函数也会被调用。
如何实现动态绑定的?
#include <iostream> using namespace std; class Base { public://即使这里修改成为private,也能访问。因为这里是根据内存模型推算出来的。 virtual void Fun1() { cout<<"Base::Fun1.."<<endl; } virtual void Fun2() { cout<<"Bae::Fun2.."<<endl; } int data1; }; class Derived:public Base { public: virtual void Fun2()//即使不加virtual 也是虚函数 { cout<<"Derived::Fun2.."<<endl; } virtual void Fun3()//即使不加virtual 也是虚函数 { cout<<"Derived::Fun3.."<<endl; } int data2; }; typedef void(*FUNC)(); int main(void) { cout<<sizeof(Base)<<endl; //8 cout<<sizeof(Derived)<<endl;//12 //基类只有一个数据成员,正常情况下,应该是4个字节?为什么是8个字节? //原因 是:头四个字节 存放指向虚表的指针 //虚表和虚基类表是不一样的。虚基类表实在虚继承的情况下产生的。 //虚表存放的是什么呢? // 存放的是虚函数 这就是基类的内存模型。 //验证 基类 Base b; long** p=(long**)&b;//对基类的地址做一个转换。指针的指针 存放的是一个指针,指针指向一个表格 FUNC fun=(FUNC)p[0][0];//指向基类的虚函数 FUNC 函数指针类型 fun();//调用 base: fun1 fun=(FUNC)p[0][1]; fun();//调用base :fun2 //验证派生类 cout<<"========"<<endl; Derived d; p=(long**)&d; fun=(FUNC)p[0][0];//base fun1 fun(); fun=(FUNC)p[0][1];//derived fun2 fun(); fun=(FUNC)p[0][2];//derived fun3 fun(); Base* pp=&d;//基类指针指向派生类对象,取出对象的头四个字节,取出虚表,在虚表中,调用Dervider的Fun2();,而不是基类的Fun2();从而达到动态绑定。调用派生类虚函数 pp->Fun2();//运行时期决定函数的入口地址。 cout<<"========"<<endl; //d.Fun2();//直接调用不会动态绑定 只能通过基类指针或者引用 //虚函数为什么不能声明为静态? //静态函数没有this 指针。Base::Fun2();没有this 指针。不是对象的一部分。就没有办法取出 对象的头四个字节 虚表指针,就没法取出虚表。 同样友元也不行 return 0; }
像上转型的时候存在对象切割的问题。派生类特有的成员消失了。
#include <iostream> using namespace std; class CObject { public: virtual void Serialize() { cout<<"CObject::Serialize"<<endl; } }; class CDocument :public CObject { public: int data1; void func() { cout<<"Document::func..."<<endl; Serialize(); } virtual void Serialize() { cout<<"Document Serialize"<<endl; } }; class CMyDoc :public CDocument { public: int data2; virtual void Serialize() { cout<<"CMyDoc Serialize"<<endl; } }; int main(void) { CMyDoc mydoc; CMyDoc* pmydoc=new CMyDoc; cout<<"test1..."<<endl; mydoc.func();//Document::func.. CMyDoc Serialize cout<<"test2..."<<endl; ((CDocument*)(&mydoc))->func();//Document::func.. CMyDoc Serialize cout<<"test3..."<<endl;//Document::func.. CMyDoc Serialize pmydoc->func(); cout<<"test4..."<<endl; ((CDocument)mydoc).func();//Document::func.. Document Serialize return 0; }
#include <iostream> using namespace std; class CObject { public: virtual void Serialize() { cout<<"CObject::Serialize"<<endl; } }; class CDocument :public CObject { public: int data1; void func() { cout<<"Document::func..."<<endl; Serialize(); } virtual void Serialize() { cout<<"Document Serialize"<<endl; } CDocument()//提供了拷贝构造函数,也必须要有默认构造函数 否则CMyDoc 在构造的时候,无法构造基类对象 { } CDocument(const CDocument& other) { cout<<" CDocument& other"<<endl; } }; class CMyDoc :public CDocument { public: int data2; virtual void Serialize() { cout<<"CMyDoc Serialize"<<endl; } }; int main(void) { CMyDoc mydoc; CMyDoc* pmydoc=new CMyDoc; cout<<"test1..."<<endl; mydoc.func();//Document::func.. CMyDoc Serialize cout<<"test2..."<<endl; ((CDocument*)(&mydoc))->func();//Document::func.. CMyDoc Serialize cout<<"test3..."<<endl;//Document::func.. CMyDoc Serialize pmydoc->func(); cout<<"test4..."<<endl; ((CDocument)mydoc).func();//Document::func.. Document Serialize //这里mydoc 对象强制转换为CDocument 对象,向山转型。派生类特有成员消失 //就连虚表也发生了变化. 完完全全将派生类对象转化为了基类对象 //CDocument会调用拷贝构造函数 return 0; }
相关文章推荐
- C++ 虚函数 多态
- C++对象布局及多态实现探索之虚函数调用
- C++通过虚函数实现多态
- C++虚函数和多态学习笔记
- C++ 虚函数 多态
- C++虚函数和多态学习笔记
- C++ 虚函数 多态
- C++ 虚函数 多态
- C++特性探寻-多态和虚函数
- C++、JAVA与C#中的多态虚函数、纯虚函数(抽象函数)
- C++ 虚函数 多态
- C++对象布局及多态实现之带虚函数的类
- 读书笔记-Thinking in C++-第15章 多态和虚函数
- 搞清楚C++继承、多态、虚函数、纯虚函数
- C++ 虚函数 多态
- C++ 虚函数 多态
- C++虚函数和多态
- C++特性探寻-多态和虚函数
- C++ 虚函数与多态
- 详解C++中的多态、虚函数、父类子类