9.C++虚函数和多态

  1. 虚函数与虚函数表

    1. 什么是虚函数? 用virtual 修饰的成员函数叫做虚函数

    2. 虚函数对于类的影响

      • 增加一个指针的内存,32位4个字节 ,64位就是8个字节

    3. 虚函数表(了解一下): 就是一个指针存储所有虚函数的首地址

    4. #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;
      }
  2. 虚函数与多态

    1. 多态定义: 同一种行为(调用)导致的不同的结果

    2. 多态的必要性原则

      • 必须父类存在虚函数

      • 子类必须采用public继承

      • 必须存在指针的引用(使用)

    3. #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;
      }

  3. 纯虚函数与ADT(Abstract Data Type)

    1. 纯虚函数也是虚函数只是纯虚函数是没有函数体的
      virtual 返回值类型 函数名()=0;
    2. 抽象类: 具有至少一个纯虚函数的类,叫做抽象类

      • 抽象类不能构建对象

      • 抽象类可以构建对象指针

    3. 纯虚函数没有被重写,无论被继承多少次 都是纯虚函数,虚函数无论被继承多少次都是虚函数

    4. #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;
      }

  4. 虚析构函数

    1. 在用子类对象初始化父类指针,父类需要虚析构函数做内存释放
    2. #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;
      }

  5. overdide与final

    1. final
      1. final:禁止重写
      2.  final子类不能存在同名函数
    2. override
      1. 强制重写,标识作用,用检查父类中是否存在当前的虚函数
      2. 若父类不存在同名虚函数,会报错
    3. #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;
      }
  6. C++类型转换

    1. 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;
      }

    2. 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;
      }

    3. 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;
      }

    4. 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;
      }

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值