-
虚函数与虚函数表
-
什么是虚函数? 用virtual 修饰的成员函数叫做虚函数
-
虚函数对于类的影响
-
增加一个指针的内存,32位4个字节 ,64位就是8个字节
-
-
虚函数表(了解一下): 就是一个指针存储所有虚函数的首地址
-
#include<iostream> #include <string> using namespace std; class studentA { public: void print1() { cout << "普通函数" << endl; } protected: private: }; class studentB { public: virtual void print1() { cout << "虚函数1" << endl; } virtual void print2() { cout << "虚函数2" << endl; } protected: private: }; int main() { cout << sizeof(studentA) << endl;//空的类、结构体 普通函数 占用1字节 cout << sizeof(studentB) << endl;//虚函数增加一个指针的内存,32位4个字节 ,64位就是8个字节,存储所有虚函数的首地址 //虚函数表 typedef void(*PF)(); studentB stu; int** vptr = (int**)&stu; PF func1 = (PF)vptr[0][0]; func1(); PF func2 = (PF)vptr[0][1]; func2(); return 0; }
-
-
虚函数与多态
-
多态定义: 同一种行为(调用)导致的不同的结果
-
多态的必要性原则
-
必须父类存在虚函数
-
子类必须采用public继承
-
必须存在指针的引用(使用)
-
-
#include<iostream> #include <string> using namespace std; class Shape { public: virtual void test1() { cout << "基类 测试函数1" << endl; } void test2() { cout << "基类 测试函数2" << endl; } protected: private: }; class Rect :public Shape { public: void test1() { cout << "子类 测试函数1" << endl; } void test2() { cout << "子类 测试函数2" << endl; } protected: private: }; int main() { //正常访问不存在多态,就近原则 Shape shape; shape.test1(); shape.test2(); Rect rect; rect.test1(); rect.test2(); //指针正常访问,就近原则 Shape* pshape = new Shape; pshape->test1(); pshape->test2(); Rect* prect = new Rect; prect->test1(); prect->test2(); // 子类对象初始化父类指针 //有virtual看对象类型,没有virutal看指针 Shape* pShape = new Rect; pShape->test1(); //是虚函数 访问子类函数 pShape->test2(); //不是虚函数 访问基类函数 return 0; }
-
-
纯虚函数与ADT(Abstract Data Type)
- 纯虚函数也是虚函数只是纯虚函数是没有函数体的
virtual 返回值类型 函数名()=0;
-
抽象类: 具有至少一个纯虚函数的类,叫做抽象类
-
抽象类不能构建对象
-
抽象类可以构建对象指针
-
-
纯虚函数没有被重写,无论被继承多少次 都是纯虚函数,虚函数无论被继承多少次都是虚函数
-
#include<iostream> #include <string> using namespace std; #define PI 3.14 class Shape { public: //纯虚函数就是做ADT(abstract data type 抽象数据类型)过程 virtual void Draw() = 0; virtual void perimeter() = 0; virtual void area() = 0; protected: private: }; class Rect :public Shape { public: Rect(int Width = 0, int Height = 0) :Shape(), Width(Width), Height(Height) {} Rect(const Rect& rect) { Width = rect.Width; Height = rect.Height; } //子类想要创建对象,必须重写父类的纯虚函数 //ADT: 具有强迫性,所有子类重写函数必须和父类的一模一样 void Draw() { cout << "绘制矩形" << endl; cout << "长:" << Width << " " << "高:" << Height << endl; } void perimeter() { cout << "周长:" << 2 * (Width + Height) << endl;; } void area() { cout << "面积:" << Height * Width << endl;; } //可以增加别的函数 //可以增加别的成员 protected: int Width; int Height; private: }; class Circle :public Shape { public: Circle(int Radius = 0) :Radius(Radius) {} Circle(const Circle& circle) { Radius = circle.Radius; } void Draw() { cout << "圆形" << endl; cout << "半径:" << Radius << endl; } void perimeter() { cout << "周长:" << 2 * PI * Radius << endl;; } void area() { cout << "面积:" << PI * Radius * Radius << endl;; } protected: int Radius; private: }; //统一访问接口 class Drawer { public: void Draw(Shape* shape) { shape->Draw();//传进来的是那个子类的对象,就会实现那个子类里面的函数 } void perimeter(Shape* shape) { shape->perimeter(); } void area(Shape* shape) { shape->area(); } protected: private: }; int main() { Shape* shape = new Rect(20, 10); shape->Draw(); shape->perimeter(); shape->area(); Drawer* drawer = new Drawer; Rect* rect1 = new Rect(20, 10); drawer->Draw(rect1);//相当于Shape* shape = new Rect(20, 10); shape->Draw(); drawer->perimeter(rect1); drawer->area(rect1); Circle* circle = new Circle(10); drawer->Draw(circle); drawer->perimeter(circle); drawer->area(circle); return 0; }
- 纯虚函数也是虚函数只是纯虚函数是没有函数体的
-
虚析构函数
- 在用子类对象初始化父类指针,父类需要虚析构函数做内存释放
-
#include<iostream> #include <string> using namespace std; class Parent { public: virtual ~Parent() { cout << "父类析构" << endl; } void print() { cout << "基类" << endl; } protected: private: }; class Son:public Parent { public: ~Son() { cout << "子类析构" << endl; } void print() { cout << "子类" << endl; } protected: private: }; int main() { //在用子类对象初始化父类指针,父类需要虚析构函数做内存释放 Parent* parent = new Son; parent->print(); delete parent; return 0; }
-
overdide与final
- final
- final:禁止重写
- final子类不能存在同名函数
- override
- 强制重写,标识作用,用检查父类中是否存在当前的虚函数
- 若父类不存在同名虚函数,会报错
-
#include <iostream> using namespace std; class A { public: //final:禁止重写 //final子类不能存在同名函数 virtual void print() final { cout << "禁止重写" << endl; } virtual void printData() {} }; class B :public A { public: //限制子类不能重写函数 //void print() //{ //} //强制重写,标识作用,用检查父类中是否存在当前的虚函数 //不存在 就会报错 void printData() override { cout << "表示当前函数是重写函数" << endl; } }; int main() { B b; A a; a.print(); b.print(); return 0; }
- final
-
C++类型转换
-
const_cast
#include<iostream> #include <string> #include <stdio.h> using namespace std; class A { public: A(const char*str):str(const_cast<char*>(str)){} void print() { cout << str << endl; } protected: char* str; private: }; class B { public: B(int num) :num(num) {} void print() { cout << num << endl; } protected: int num; }; int main() { //去掉const属性 //1.作用普通指针 const int num = 12; int* pNum = const_cast<int*>(&num); *pNum = 15; cout << &num << endl; cout << pNum << endl; cout << num << endl;//num依旧是12 cout << *pNum << endl;//15 //2.操作类中的char*类型指针 A object("HelloWorld"); object.print(); char str[] = "Hello"; A object1(str); object1.print(); //3.操作类指针 const B* pB = new B(10); //pB->print(); //常对象指针只能调用常成员函数 B* ppB = const_cast<B*>(pB); ppB->print(); //4.操作常量引用 int a=12; const int& b = a; int& c = const_cast<int&>(b); cout << c << endl;; //5.加上const属性 int aa = 11; int *pa = &aa; const int* ppa = const_cast<const int*>(pa); cout << *ppa; return 0; }
-
static_cast
#include <iostream> using namespace std; /* static_cast<要转换的类型>(要转换的目标) 1.基本数据类型转换(类似C语言强制类型转换) 2.把空指针转换成目标类型指针 3.把任何类型的变量转换为void类型 4.用在类上面的转换(基类和派生类对象之间的转换) 4.1 进行上行转换(从子到父 指针或者引用转换) 安全 4.2 进行下行转换(从父到子 指针或者引用转换) 注意点:static_cast不能去掉const */ class Parent { public: void print() { cout << "parent" << endl; } void printParent() { cout << "parent1" << endl; } }; class Son :public Parent { public: void print() { cout << "son" << endl; } void printData() { cout << "son2" << endl; } }; int main() { //1.基本数据类型 char cNum = 'A'; int iNum = static_cast<int>(cNum); cout << iNum << endl; //2.空类型指针 double* pD = new double; void* pVoid = static_cast<void*>(pD); //3.const类型转换 int x = 10; const int constNum = static_cast<const int>(x); //4.错误用法 const int xx = 0; //int* p = static_cast<int*>(&xx);// 去掉const 必须用const_cast //5.从子到父 Parent* p = new Son; p->print(); Son* pson = new Son; p = static_cast<Parent*>(pson); p->print(); Parent* parent = new Parent; Son* son = static_cast<Son*>(parent); son->print(); son->printData(); son->printParent(); return 0; }
-
dynamic_cast
#include <iostream> #include <string> using namespace std; /* dynamic_cast<要转换类型>(要转换的东西) 1.上行转换 和static_cast一样的 2.下行转换 dynamic_cast更安全 3.交叉转换 多继承 */ class Parent { public: Parent(string pName = "父类") :pName(pName) {} virtual void print() { cout << pName << endl; } protected: string pName; }; class Son :public Parent { public: Son(string sName = "子类") :sName(sName) {} virtual void print() { cout << sName << endl; } //void printData() { cout << gName << endl; } protected: string sName; }; class A { public: virtual void print() { cout << "A" << endl; } }; class B { public: virtual void print() { cout << "B" << endl; } }; class C :public A, public B { public: void print() { cout << "C"; } }; int main() { Parent* parent = new Parent; Son* son = new Son; //1.上行转换 Parent* pStatic = static_cast<Parent*>(son); Parent* pDyn = dynamic_cast<Parent*>(son); pStatic->print(); pDyn->print(); //2.下行转换 Son* pStatic1= static_cast<Son*>(parent); //不存在virtual 不会报错 pStatic1->print(); //不存在virtual 会中断 Son* pDyn1 = dynamic_cast<Son*>(parent); //dynamic_cast检查父类中是否存在virutal 不存在 类型转换直接错误 //下行转换,调用子类中父类没有函数会报错 if (pDyn1 != nullptr) { pDyn1->print(); } //3.交叉转换 A* a = new C; B* b = dynamic_cast<B*>(a); b->print(); return 0; }
-
reinterpret_cast
#include <iostream> using namespace std; int Max(int a, int b) { return a > b ? a : b; } int main() { //把一个指针转换成一个整数,也可以把一个整数转换成一个指针 int num = reinterpret_cast<int>(Max); cout << num << endl; cout << Max << endl; //先把一个指针转换成一个整数,再把该整数转换成原类型的指针,还可以得到原先的指针值 auto pMax = reinterpret_cast<int(*)(int, int)>(num); cout << pMax(1, 2) << endl; return 0; }
-
9.C++虚函数和多态
最新推荐文章于 2024-08-09 10:25:03 发布