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

怎么用手机做刷会员网站优化关键词可以选择哪个工具

怎么用手机做刷会员网站,优化关键词可以选择哪个工具,国外创意包装设计欣赏,微博优惠券网站怎么做的本章目标 1.多态的概念 2.多态的定义实现 3.虚函数 4.多态的原理 1.多态的概念 多态作为面对三大特性之一,它所指代的和它的名字一样,多种形态.但是这个多种形态更多的指代是函数的多种形态. 多态分为静态多态和动态多态. 静态多态在前面已经学习过了,就是函数重载以及模板,…

本章目标

1.多态的概念
2.多态的定义实现
3.虚函数
4.多态的原理

1.多态的概念

多态作为面对三大特性之一,它所指代的和它的名字一样,多种形态.但是这个多种形态更多的指代是函数的多种形态.
多态分为静态多态和动态多态.
静态多态在前面已经学习过了,就是函数重载以及模板,它们是在编译时就已经确定下来了,也被成为编译时多态.它们通过传不同的参数实现函数不同的形态.
我们在这里主要将动态多态,也就是运行时多态.当我们运行某个函数的时候,它会根据传过来的对象的不同,来实现不同的行为,简单来说就是统一继承体系下的不同类对象去调用同一个函数产生了不同的行为

2.多态的定义实现

2.1实现多态的条件

1.必须是基类的指针或者引用去调用虚函数
2.虚函数必须完成了重写或者覆盖
因为我们前面所将的切片的类型兼容转换,只有基类的指针或者引用才能即指向基类对象又指向派生类对象.
虚函数的重写或者覆盖所指的是它的实现重写,这样基类和派生类才能有不同的函数.
才能实现多态.

#include<iostream>
using namespace std;
class A
{
public:virtual void  a(){cout << "A" << endl;}
};
class b :public A
{
public:virtual void a(){cout << "b" << endl;}};
int main()
{A* ptr1 = new A;A* ptr2 = new b;ptr1->a();ptr2->a();return 0;
}

在这里插入图片描述

以上就是多态的实现.

3.虚函数

类成员函数,在函数的前面加上virtual修饰,我们就称之为虚函数.非类成员函数是不能用virtual修饰的.

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

3.1虚函数的重写覆盖

虚函数的重写覆盖所指的是在派生类之中有一个和基类完全的一样的虚函数(返回值,函数名,参数列表),那么就叫做虚函数的重写覆盖.
在有的地方只在基类的虚函数的地方加上virtual,而在派生类中,并没有加入virtual来进行修饰,这样也是构成重写或者覆盖的.因为从基类继承下来的虚函数,在派生类也继承下来了它的虚函数属性

3.2协变

在派生类重写基类虚函数的时候,我们可以让派生的返回类型与基类不同,去返回基类或者派生类的指针或者引用,这个指针或者引用可以是其他类的.

class A {};class B : public A {};class Person {public:virtual A* BuyTicket() 
{ 
cout << "
买票
全价
" << endl;return nullptr;}};class Student : public Person {public:virtual B* BuyTicket() 
{ 
cout << "
买票
打折
" << endl;return nullptr;}};void Func(Person* ptr){ptr->BuyTicket();}int main(){Person ps;Student st;Func(&ps);Func(&st);return 0;}

3.3析构函数的重写

只要基类的析构函数为虚函数,它的派生类的析构一定会与基类的析构函数构成重写,在前面我们说继承的时候讲到析构函数会在编译时统一将名称处理成destructor,这样它们就构成了隐藏,而在这里则是构成了重写.

#include<iostream>
using namespace std;
class A
{
public:virtual void  a(){cout << "A" << endl;}virtual ~A(){cout << "~A" << endl;}
};
class b :public A
{
public:virtual void a(){cout << "b" << endl;}~b(){delete[] arr;cout << "~b" << endl;}
private:int* arr = new int[10];
};
int main()
{A* ptr1 = new A;A* ptr2 = new b;ptr1->a();ptr2->a();delete ptr1;delete ptr2;return 0;
}

在这里插入图片描述

3.4override和final关键字

从上面我们可以看出c++对虚函数的要求比较严格,可能有的时候参数类型写错了导致无法构成重写.我们就可以override来帮助我们进行检查.
在这里插入图片描述

class D
{
public:virtual void  d(){cout << "dadad" << endl;}
};
class E:public D
{
public:virtual void d(int a) override{cout << "dada" << endl;}
};

final关键字我们已经见过了,我们在实现一个不能被继承的类的时候,我们用final修饰或者构造私有.
而在这里我们不想让虚函数被继承也可用final来进行修饰.
在这里插入图片描述

3.5重载/重写/隐藏对比

重载
1.在统一作用域
2.函数名相同,参数不同,返回值可相同,可不同
重写
1.在统一继承体系下的不同的基类和派生类的作用域之中.
2.函数名,参数,返回值都必须相同,协变例外
3.两个函数都必须时虚函数
隐藏
1.在统一继承体系下的不同的基类和派生类的作用域之中.
2.函数名相同
3.两个函数只要不是重写就是隐藏.
4.变量名相同也可以构成隐藏

隐藏和重写的二者上是有所重叠但是并不完全相同

3.6纯虚函数与抽象类

在虚函数的后面加上=0,这个虚函数就是纯虚函数,纯虚函数所在的类被称为抽象类,抽象类是不能够实例化对象的,并且抽象类被继承之后的派生类的虚函数一定要被重写.
否则这个类也是抽象类.

class F
{
public:virtual void ff() = 0;};
class G :public F
{virtual void ff(){cout << "dada" << endl;}
};

在这里插入图片描述

4.多态的原理

class Base{public:virtual void Func1(){cout << "Func1()" << endl;}protected:int _b = 1;char _ch = 'x';};

当我们去算上面的类的时候,我们正常的结果是8bytes.
实际上则不同
在这里插入图片描述
它的大小是12bytes.
在这里插入图片描述
当我们创建一个Base类的对象来看的时候,我们发现除了上面的我们类中创建两个成员变量还有一个vfptr的函数指针.在x86的环境下它的大小就是12bytes.
这个指针就是虚函数表指针,每一个含有虚函数的类中,至少含有一个虚函数表,这个表里面放在虚函数的地址
在这里插入图片描述
从底层的角度我们该如何看到a是如何被调用的呢,当父类指针ptr1指向A的时候调用A的a函数,ptr2指向b的时候调用b中的a函数呢.
实际上当调用虚函数的时候,去调用函数的地址的时候,不是编译时通过对象来确定虚函数的地址.而是通过对象中的虚表来去call这个虚函数的地址

class Person {public:virtual void BuyTicket() { cout << "买票全价" << endl; }private:   
string _name;};class Student : public Person {public:virtual void BuyTicket() { cout << "买票打折" << endl; }private:   
string _id;};class Soldier: public Person {public:virtual void BuyTicket() { cout << "买票优先" << endl; }private:   
string _codename;};void Func(Person* ptr){// 这⾥可以看到虽然都是Person指针Ptr在调⽤BuyTicket 
// 但是跟ptr没关系,⽽是由ptr指向的对象决定的。ptr->BuyTicket();}int main(){// 其次多态不仅仅发⽣在派⽣类对象之间,多个派⽣类继承基类,重写虚函数后// 多态也会发⽣在多个派⽣类之间。Person ps;Student st;Soldier sr;Func(&ps);Func(&st);Func(&sr);return 0;}

4.1动态绑定与静态绑定

对于通过动态多态(父类的指针或者引用)去调用的函数,也就是运行时到指定对象的虚函数表中去调用函数的,我们叫做动态绑定.
对不满足动态多态条件的在编译时确定函数地址或者通过对象去确定函数的地址的,我们叫做静态绑定

4.2虚函数表

1.基类的虚函数表中存放着所以基类虚函数的地址,同一类型的对象公用同一张虚表,不同类的虚表之间时独立的.基类和派生类的虚表时相互独立的
2.派⽣类由两部分构成,继承下来的基类和⾃⼰的成员,⼀般情况下,继承下来的基类中有虚函数表指针,⾃⼰就不会再⽣成虚函数表指针。但是要注意的这⾥继承下来的基类部分虚函数表指针和基类对象的虚函数表指针不是同⼀个,就像基类对象的成员和派⽣类对象中的基类对象成员也独⽴的。
3.派⽣类中重写的基类的虚函数,派⽣类的虚函数表中对应的虚函数就会被覆盖成派⽣类重写的虚函数地址。
4.派⽣类的虚函数表中包含,(1)基类的虚函数地址,(2)派⽣类重写的虚函数地址完成覆盖,派⽣类⾃⼰的虚函数地址三个部分。
5.虚函数表本质是⼀个存虚函数指针的指针数组,⼀般情况这个数组最后⾯放了⼀个0x00000000标记。(这个C++并没有进⾏规定,各个编译器⾃⾏定义的,vs系列编译器会再后⾯放个0x00000000标记,g++系列编译不会放)
6.虚函数存在哪的?虚函数和普通函数⼀样的,编译好后是⼀段指令,都是存在代码段的,只是虚函数的地址⼜存到了虚表中。
7.虚函数表存在哪的?这个问题严格说并没有标准答案C++标准并没有规定,我们写下⾯的代码可以对⽐验证⼀下。vs下是存在代码段(常量区)

class Base {public:virtual void func1() { cout << "Base::func1" << endl; }virtual void func2() { cout << "Base::func2" << endl; }void func5() { cout << "Base::func5" << endl; }protected:int a = 1;};class Derive : public Base{public:// 重写基类的func1 
virtual void func1() { cout << "Derive::func1" << endl; }virtual void func3() { cout << "Derive::func1" << endl; }
int main(){int i = 0;static int j = 1;int* p1 = new int;const char* p2 = "xxxxxxxx";printf("栈:%p\n", &i);printf("静态区:%p\n", &j);printf("堆:%p\n", p1);printf("常量区:%p\n", p2);Base b;Derive d;Base* p3 = &b;Derive* p4 = &d;printf("Person虚表地址:%p\n", *(int*)p3);printf("Student虚表地址:%p\n", *(int*)p4);printf("虚函数地址:%p\n", &Base::func1);printf("普通函数地址:%p\n", &Base::func5);return 0;}
http://www.dtcms.com/wzjs/37884.html

相关文章:

  • 网站建设有哪些方面抖音推广公司
  • 怎么用vs2017做网站网站优化排名优化
  • 成都哪里有做网站建设的怎样进行seo优化
  • 微网站哪家好外贸业务推广
  • 搜狗网站提交设计公司网站模板
  • 网站开发考核站内seo和站外seo区别
  • 如何做优酷网站赚钱营销网络推广方式有哪些
  • 外贸五金网站重庆今天刚刚发生的重大新闻
  • 用什么网站可以做链接免费建立个人网站凡科
  • 网站的模块怎么做百度搜索百度
  • brushed网站模板磁力兔子搜索引擎
  • 做整装的网站品牌营销包括哪些内容
  • 网站模版 之星百度账号怎么改用户名
  • 青海网站建设公司多少钱强强seo博客
  • 建立传媒公司网站在线资源链接
  • 万网如何做网站宁波网络推广联系方式
  • 做网站和做app那个简单企业营销模式
  • 长沙高端网站建设服务标题关键词优化技巧
  • 电子商务网站建设技巧酒店推广渠道有哪些
  • 长春手机建站模板百度竞价排名是什么意思
  • 网站开通银行支付接口外链推广平台
  • seo网站制作中国十大企业培训机构排名
  • 宜春网站开发公司电话网页制作成品模板网站
  • 可信赖的做网站长沙seo平台
  • 快递公司网站怎么做外链发布网站
  • bootstrap 网站开发目前较好的crm系统
  • 企业网站建设的报价怎样做推广
  • 广州网站建设系统青海网站seo
  • 网站是用什么语言写的数据分析师就业前景
  • 网站名称设置交换链接营销