override和overwrite实例代码
#include <iostream> using namespace std; class Base { public: virtual void func1() { cout << "Base::func1" << endl; } void func2() { cout << "Base::func2" << endl; } }; class Drived : public Base { public: void func1() { cout << "Drived::func1" << endl; } void func2() { cout << "Drived::func2" << endl; } }; int main() { Base* base; Drived drived; base = &drived; base->func1(); // 是虚函数,基类指针指向派生类对象,调用的派生类对象的虚函数,override base->func2(); // 是非虚函数,根据p指针实际类型来调用相应类的成员函数,overwrite return 0; } /* Drived::func1 Base::func2 */
虚析构函数
#include <iostream> using namespace std; class Base { public: Base() { cout << "Base Constructor" << endl; } virtual ~Base() { cout << "Base Destructor" << endl; } // 如果一个类要作为多态基类,要将析构函数作为虚析构函数 virtual void func1() { cout << "Base::func1" << endl; } void func2() { cout << "Base::func2" << endl; } }; class Derived : public Base { public: Derived() { cout << "Derived Constructor" << endl; } ~Derived() { cout << "Derived Destructor" << endl; } void func1() { cout << "Derived::func1" << endl; } void func2() { cout << "Derived::func2" << endl; } }; int main() { Base* base; base = new Derived; base->func1(); base->func2(); delete base; } /* 如果析构函数不是虚析构函数,那么在delete base指针的时候,只会调用Base类的析构函数, 但是在开辟Derived空间的时候,也可能会在堆上创建内存,所以也需要释放内存 */
虚表指针
#include <iostream> using namespace std; #pragma pack(push) //保存对齐状态 #pragma pack(8) //设定为8字节对齐 class Base { public: virtual void func1() { cout << "Base::func1" << endl; } virtual void fun2() { cout << "Base::func2" << endl; } int baseData_; }; #pragma pack(pop) //恢复对齐状态 class Derived : public Base { public: virtual void func2() { cout << "Derived::func2" << endl; } virtual void func3() { cout << "Derived::func3" << endl; } int derivedData_; }; typedef void (*FUNC)(); int main() { Base* basePoint; long long** point = (long long**)(&basePoint); FUNC fun = (FUNC)point[0][0]; fun(); return 0; }
基类声明为虚函数之后,其派生类不管有没有
virtual
关键字,其函数都是虚函数。存在虚函数的类,内存模型中前4个字节(64位系统指针是8个字节)存放虚表指针,虚表中存放的是虚函数。如果是派生类中,虚表指针的指向的虚表存放的是基类的虚函数,覆盖的虚函数,自己的虚函数。
对象切割、转换
#include <iostream> using namespace std; class CObject { public: virtual void func() { cout << "CObject func" << endl; } }; class CDocument : public CObject { public: void normalFunc() { cout << "CDocument func" << endl; func(); } virtual void func() { cout << "CDocument func" << endl; } }; class CMyDoc : public CDocument { public: virtual void func() { cout << "CMyDoc func" << endl; } }; int main() { CMyDoc myDoc; CMyDoc* pmyDoc = new CMyDoc; cout << "# Test 01" << endl; myDoc.func(); cout << "# Test 02" << endl; ((CDocument*)&myDoc)->func(); // 等同指向派生类的基类指针 cout << "# Test 03" << endl; pmyDoc->func(); cout << "# Test 04" << endl; // 向上转换,完完全全将一个派生类对象转换成一个基类对象 // 虚表指针也发生了变化 ((CDocument)myDoc).func(); return 0; }