当前位置: 首页 > news >正文

企业网站 flash个人网站模板

企业网站 flash,个人网站模板,江苏省建设厅纪委网站,定制软件开发公司介绍C(进阶) 第2章 多态 文章目录 前言一、多态的概念二、多态的定义及实现1.虚函数2.虚函数的重写3.多态的条件4.多态的细节 三、析构函数的重写四、重载/重写/隐藏的对比五、抽象类抽象类 六、相关题目题目1题目2 七、const修饰八、多态原理九、虚函数放在地方总结 前…

C++(进阶) 第2章 多态


文章目录

  • 前言
  • 一、多态的概念
  • 二、多态的定义及实现
    • 1.虚函数
    • 2.虚函数的重写
    • 3.多态的条件
    • 4.多态的细节
  • 三、析构函数的重写
  • 四、重载/重写/隐藏的对比
  • 五、抽象类
    • 抽象类
  • 六、相关题目
      • 题目1
      • 题目2
  • 七、const修饰
  • 八、多态原理
  • 九、虚函数放在地方
  • 总结


前言

什么是多态?多态其实就是多种形态的简写这篇博客会详细的介绍多态


一、多态的概念

多态(polymorphism)的概念:通俗来说,就是多种形态。多态分为编译时多态(静态多态)和运⾏时多态(动态多态),这⾥我们重点讲运⾏时多态,编译时多态(静态多态)和运⾏时多态(动态多态)。编译时多态(静态多态)主要就是我们前⾯讲的函数重载和函数模板,他们传不同类型的参数就可以调⽤不同的函数,通过参数不同达到多种形态,之所以叫编译时多态,是因为他们实参传给形参的参数匹配是在编译时完成的,我们把编译时⼀般归为静态,运⾏时归为动态。
通俗点来说就是不同的东西做不同的事情有多种形态


二、多态的定义及实现

1.虚函数

类成员函数前⾯加virtual修饰,那么这个成员函数被称为虚函数。注意⾮成员函数不能加virtual修饰。
这是构成多态的必备条件之一

class Person{public:virtual void BuyTicket() { cout << "买票-全价" << endl; }};

2.虚函数的重写

这里学生类继承了person类那么这里按之前的理解应该构成隐藏关系但是这里不一样,这里我们一般叫做重写

class Person{public:virtual void BuyTicket() { cout << "买票-全价" << endl; }};
class Student : public Person 
{
public:virtual void BuyTicket() { cout << "买票-打折" << endl; }
};

假如我现在要去买票

class Person{public:virtual void BuyTicket() { cout << "买票-全价" << endl; }};
class Student : public Person 
{
public:virtual void BuyTicket() { cout << "买票-打折" << endl; }
};void func(Person& p)
{p.BuyTicket();
}
int main()
{Person p;Student s;func(p);func(s);return 0;
}

注意看这里传入的是父类

在这里插入图片描述

这里可能会有疑问为什么func函数参数写的父类但是这里传入子类也可以这是因为切片
在这里插入图片描述
这里可以看到传入不同的类型处理的方式也不一样这里就是一个简单的多态


3.多态的条件

  1. 虚函数的重写
  2. 必须是父类的指针或者是引用
  3. 上面俩个条件缺一不可

4.多态的细节

假如这里把父类的virtual去掉这里是多态吗?

class Person{public:void BuyTicket() { cout << "买票-全价" << endl; }};
class Student : public Person 
{
public:virtual void BuyTicket() { cout << "买票-打折" << endl; }
};void func(Person& p)
{p.BuyTicket();
}
int main()
{Person p;Student s;func(p);func(s);return 0;
}

这里的答案是:不是多态
在这里插入图片描述


假如这里子类去掉virtual是多态吗?

在这里插入图片描述


答案是:是多态
在这里插入图片描述


面试题就很喜欢这样考,但是这里是为什么父类去就不行子类就行呢?

上面那样构成虚函数的重写就算不写virtual,因为继承了父类子类哪里会把父类的声明拿下来也是属于多态


多态调用:看指向对象类型,指向谁调用谁的虚函数
普通调用:看调用者的类型,调用调用者的函数

三、析构函数的重写

假如这里有1父1子

class person
{
public:~person(){cout << "~person()" << endl;}};class student:public person
{
public:~student(){cout << "~student()" << endl;}
};int main()
{person* p1 = new student;delete p1;
}

在这里插入图片描述
这里定义了一个指针指向了student这里
在这里插入图片描述
但是这里调用的是父类的析构函数

上面这里会出现非常大的问题上面的代码是为了方便理解

假如我把代码改成这样

class person
{
public:~person(){cout << "~person()" << endl;}};class student:public person
{
public:~student(){delete[] _ptr;cout << "~student()" << endl;}
protected:int* _ptr = new int[10];
};int main()
{person* p1 = new student;delete p1;
}

在这里插入图片描述
可以看到这里就出现了很严重的内存泄露


按正常关系来说studen继承了person,这studen就应该有俩个析构函数一个自己的一个父类的但是这里为什么只调用了一个

这里是因为,析构函数会被编译器统一处理成destructor()那么这里就有俩个destructor函数这里就会成隐藏关系
所以这里就只会调用父类的析构函数


这里的解决方式就是加上virtual
在这里插入图片描述

在这里插入图片描述

四、重载/重写/隐藏的对比

在这里插入图片描述


五、抽象类

抽象类

class Car
{
public:virtual void Drive() = 0;
};

这就是一个抽象类,在虚函数的后⾯写上 =0 ,则这个函数为纯虚函数,纯虚函数不需要定义实现(实现没啥意义因为要被派⽣类重写,但是语法上可以实现),只要声明即可。


抽象类也无法实例化,这里就会有一个疑问了,那有个蛋用呢?
在这里插入图片描述


如果我不想让别人实例化出car类出来但是可以实例化benz出来就可以用抽象派去重写,继承的benz类是可以实例化的

class Car
{
public:virtual void Drive() = 0;
};class Benz : public Car
{
public:virtual void Drive(){cout << "Benz-舒适" << endl;	}
};
int main()
{Benz a;
}

先来俩题热热身

六、相关题目

题目1

class A
{
public:virtual void func(int val = 1){cout << "A->" << val << endl;}virtual void test(){func();}
};class B : public A
{
public:void func(int val = 0){cout << "B->" << val << endl;}
};int main()
{B* p = new B;p->test();return 0;}

在这里插入图片描述

答案是B

在这里插入图片描述


这里就是c++语法的一个大坑,用的是B类,但是这里是继承的test会去找子类的,但是可以发现子类哪里是可以不写virtual的,用的是子类的定义,但是声明依旧用的是父类的


题目2

class Base
{
public:virtual void Fun1(){cout << "Func1" << endl;}
private:int _a = 1;char ch = '1';};int main()
{cout << sizeof(Base) << endl;
}

在这里插入图片描述
在这里插入图片描述
定义成虚函数了以后这里就多要一个指针
在这里插入图片描述


所以说写成虚函数就会付出代价,这个指针指向虚函数表,虚函数的地址都会放在这张表里面,多态就是靠这张虚函数表实现的


七、const修饰

纯虚函数无法实例化,这里可以强制别人用引用或者指针

class Animal
{
public:virtual void sound() = 0;
};class Cat : public Animal
{
public:virtual void sound(){cout << "Cat-喵喵" << endl;}
};
class Dog : public Animal
{
public:virtual void sound(){cout << "Dog-汪汪" << endl;}
};
void AnimalSound(Animal a)
{}

在这里插入图片描述


这里加上const可以使用匿名对象

class Animal
{
public:virtual void sound() const  = 0;
};class Cat : public Animal
{
public:virtual void sound()const {cout << "Cat-喵喵" << endl;}
};
class Dog : public Animal
{
public:virtual void sound()const {cout << "Dog-汪汪" << endl;}
};
void AnimalSound(const Animal& a)  
{a.sound();
}
int main()
{AnimalSound(Cat());return 0;
}

在这里插入图片描述


八、多态原理

上面说到多态必须是要虚函数并且形参还需要是父类的引用或者指针,那么这个虚函数和普通的函数有什么区别呢?

在这里插入图片描述

这里可以看到这里除了成员变量_a外还有一个_vfptr,这里面还放着成员函数的,这个东西其实就是一个指针数组,这个指针会指向一个表这个表就是虚表


下面俩个是虚函数一个不是,这里用监视窗口查看一下

class Base
{
public:virtual void Func1(){cout << "Base::Func1" << endl;}virtual void Func2(){cout << "Base::Func2" << endl;}void Func3(){cout << "Base::Func3" << endl;}
private:int _a;};int main()
{Base b;return 0;
}

在这里插入图片描述
这里可以通过上面看到这个表里面只有俩个函数


用内存窗口是可以看见的
在这里插入图片描述


多态其实就是动态确定地址

举个例子

class Base
{
public:virtual void Func1(){cout << "Base::Func1" << endl;}virtual void Func2(){cout << "Base::Func2" << endl;}void Func3(){cout << "Base::Func3" << endl;}
private:int _a;};
class Derive : public Base
{
public:virtual void  Func1(){cout << "Derive::Func1" << endl;}
private:int _b;
};
void Func1(Base* p)
{p->Func1();//虚函数p->Func3();//不是虚函数
}int main()
{Func1(new Base);Func1(new Derive);return 0;
}

在这里插入图片描述

在这里插入图片描述
这里可以看见func1是重写后的那个func1但是这里的func3是不会重写的

第二个func1是重写后的那个func也就是谁调用那个虚表就指向,
第二个调用的时候我这里给的参数是Derive,这里会发生切片,这里就会对func1进行重写,但是这里收到的参数始终都是一个base指针,只不过这里可能是子类切片出来的,切片和不是切片出来的这里就会出现虚表地址不同

所以这里就叫运行时绑定也叫多态绑定,这里就可以指向父类调用父类,指向子类就调用子类,它能调用不同的函数,它本质的原因就是因为那个虚表的地址不同

这也就是为什么函数的参数必需要父类的指针或者引用的原因
在这里插入图片描述

九、虚函数放在地方

  1. 虚函数 ------------代码段
  2. 虚函数表 --------代码段
  3. 虚函数表的指针-类对象

总结

多态看起来复杂其实只要理解了虚表这个东西就不会复杂,虚函数就有一个指针数组,这里面放着虚表的地址,然后这些虚表里面放着虚函数的地址,然后在通过切片来看是哪一个虚表的地址这就是多态的原理

http://www.khdw.cn/news/32600.html

相关文章:

  • 网站建设公司好不好怎样宣传自己的品牌
  • 哪个网站做网上旅社预定九个关键词感悟中国理念
  • 老司机的公众号推荐windows优化大师免费版
  • 合山市网站如何做好营销
  • 开发电商网站要多少钱什么是推广
  • 西安做网站那家好网络营销的六个特点
  • 如何做影视网站的标题企业新闻稿发布平台
  • 做包装的网站seo网站排名优化公司
  • 沌口网站建设seo查询网站是什么
  • 什么是crm管理系统湖南seo网站开发
  • 山东网站建设平台线下推广公司
  • 宠物主题网站模板外呼系统电销
  • 餐饮网站建设的毕设报告如何做好网上销售
  • 秦皇岛做网站seo的产品推广宣传方案
  • 上海网站建设公司费用seo的排名机制
  • 征婚网站认识的男人做定投保seo岗位职责
  • 吉林长春火车站官网网站降权查询工具
  • 网站编辑是什么工作源云推广
  • 马鞍山做公司网站的网站推广方法有哪些
  • 嵊州哪里可以做网站市场营销推广
  • 石家庄哪里做微网站构建新发展格局
  • wordpress外贸主题免费下载seo公司排行
  • 常州做网站建设今日油价92汽油价格
  • 宠物用品技术支持 东莞网站建设优化网站seo
  • 建设移动网站seo搜索优化 指数
  • 类做秋霞的网站百度百科词条创建入口
  • 最好网站开发公司厦门网站建设平台
  • 游戏的网站策划应该怎么做google 推广优化
  • 网站建设公司ipo百度竞价入口
  • 商河 网站建设百度站长平台链接