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

网站建设 域名 数据库武汉seo网站

网站建设 域名 数据库,武汉seo网站,javaweb网站开发书籍,同性性做视频网站目录 一、抽象类 1)抽象类定义 2)抽象类的继承 3)抽象类实现多态 4)抽象类的好处 二、多态的实现原理 1)虚函数的存储方式 2)子类中虚函数的存储方式 ① 子类将基类中的虚表原封不动的拷贝到自己的…

目录

一、抽象类

1)抽象类定义

 2)抽象类的继承

3)抽象类实现多态

4)抽象类的好处

二、多态的实现原理

1)虚函数的存储方式

2)子类中虚函数的存储方式

① 子类将基类中的虚表原封不动的拷贝到自己的虚表中

② 如果子类中重写了基类中的虚函数,则将子类虚表中基类的虚函数替换为子类自己重写了的虚函数地址

③ 如果子类有新增的虚函数,则接着将子类新增的虚函数按照其在子类中的声明顺序依次增加到子类虚表的尾部

 3)代码检验虚函数在虚表中的先后位置

 4)对于多态的原理的剖析

① 当不满足多态的条件时

② 满足多态的条件(通过指针或者引用调用)

 三、其他继承方式下的虚表模型

1)单继承方式

 2)多继承方式

 源码:(注意调用TestPrintB1与TestPrintB2方法获取类中虚表的顺序)


一、抽象类

在多态上那篇文章中,写了这样一个类Shape,然后通过子类圆、矩形、三角形分别继承该Shape类基类,通过重写基类中的Print与GetPerimeter这俩个虚函数然后达到了多态的效果。

可是这里仍然有一些问题,就是这个基类的函数Print与GetPerimeter这俩个函数的执行对于基类对象来说,用Shape定义一个对象s,这个s是个啥呢?它是一个图形?它是个啥图形?不免得引发争议,这个Shape就不应该定义对象,它的功能函数也不应该被实现!!!

class Shape
{
public:virtual void Print(){cout << "未知图形" << endl;}virtual double GetPerimeter(){cout << "未知图形,无法获得周长" << endl;}
};

这个Shape就是一个抽象类,形状这个概念在问题领域中不是直接存在的,它只是一个抽象概念。

1)抽象类定义

在虚函数的后面写上=0,表示该函数为纯虚函数,包含纯虚函数的类称为抽象类(也叫接口类),抽象类不能实例化出对象。

class Shape
{
public:virtual void Print() = 0;virtual double GetPerimeter() = 0;
};

 2)抽象类的继承

抽象类可以被继承,但子类中如果没有对基类所有的纯虚函数进行重写,则子类也无法进行实例化对象。(即子类也是一个抽象类)

 对基类中的所有纯虚函数进行重写之后才能完成子类实例化对象:

class Shape
{
public:virtual void Print() = 0;    // 限定为纯虚函数,表示在子类中必须要对其进行重写virtual int GetPerimeter() = 0;
};class Triangle : public Shape
{
public:Triangle(int a, int b, int c): _a(a), _b(b), _c(c){}virtual void Print()override    // 养成给基类中需要重写的虚函数加上override的习惯{cout << "△" << endl;}virtual int GetPerimeter()override{return _a + _b + _c;}
private:int _a;int _b;int _c;
};
int main()
{Triangle t(3, 4, 5);    // 正常编译
}

3)抽象类实现多态

上面说了抽象类无法实例化对象,但是抽象类也是一种类型,所以它可以创建指针或者引用。

那么就可以用到多态来传递参数

void Test(Shape& s)    // 传入Shape类型的引用
{s.Print();cout << s.GetPerimeter() << endl;
}int main()
{Triangle t(3, 4, 5);Test(t);    // 实现多态Shape s;	// 实例化对象报错 !!!Shape* ptrs = &t;	// 定义一个指针  OKShape& rs = t;	// 定义一个引用  OK  // 基类的指针或引用可以指向子类return 0;
}

4)抽象类的好处

        ①  代码更加符合逻辑——有些类就是无法创建对象,所以将它声明为抽象类

        ② 不用花费时间来考虑纯虚函数中的代码应该怎么写

        ③ 抽象类实际规范了:后续子类要实现的虚函数的原型 ==》将接口规范化

二、多态的实现原理

这里使用的是VS2019 x86 32位的编译环境下进行研究(一个指针为4个字节)

1)虚函数的存储方式

class D
{
public:D(int d, int b): _d(d){cout << "B::B()" << endl;}virtual void func1(){cout << "D::func1()" << endl;}virtual void func2(){cout << "D::func2()" << endl;}virtual void func3(){cout << "D::func1()" << endl;}int _d;
};int main()
{cout << sizeof(D) << endl;    // 结果为 8D d(1,2);return 0;
}

 创建一个D类,类中存在三个虚函数,这三个虚函数在类中的模型是如何呢?

① 调试并查看用D创建出来的对象d:发现d中前四个字节存放的是一个类似于地址的东西,接着存放的是_d的值也占用四个字节,所以sizeof(D)为8个字节

② 那么这四个字节的地址是什么呢?

展开这个地址发现里面又存放了三个地址,而这三个地址都指向了我定义的三个虚函数!

 

③ 调用内存窗口看一下&d,然后再打开另外一个窗口查看一下d中前四个字节的地址存放的是啥

 ④ 对比这内存窗口与监视窗口的这三个地址,发现就是②中所说的,这块地址指向了三个虚函数的地址。

 

 ⑤ 模型推导

 ⑥ 同一个类中定义俩个对象,它们的虚表地址是相同的。(共用同一张虚表)

 

结论:

        如果一个类中存在虚函数(类的大小多个4个字节)

        ① 则编译时编译器会为类中的虚函数创建一个虚表(编译器一定会生成类的构造方法)

        ② 虚表中的内容存放的是各个虚函数的入口地址,

        ③ 并且虚表中虚函数的先后次序和类中定义的虚函数的先后次序一致。

        ④ 同一个类中的多个对象共用同一张虚表

2)子类中虚函数的存储方式

上面了解了关于类中虚函数是如何存储的,那么下面通过继承来学习子类中的虚函数的存储方式

① 子类将基类中的虚表原封不动的拷贝到自己的虚表中

 如图将B中的俩个虚函数继承下来后置入自己的虚表中。函数访问时通过虚表指针来进行访问。

class B{
public:int _b;virtual void func1(){cout << "B::func1()" << endl;}virtual void func2(){cout << "B::func2()" << endl;}
};class D : public B{
public:int _d;
};

② 如果子类中重写了基类中的虚函数,则将子类虚表中基类的虚函数替换为子类自己重写了的虚函数地址

D子类重写了基类的虚函数func1():

③ 如果子类有新增的虚函数,则接着将子类新增的虚函数按照其在子类中的声明顺序依次增加到子类虚表的尾部

通过内存监视窗口了解虚表内的函数存储(D::func3()为在子类D中新增的虚函数,D::func1为子类重写了基类的虚函数,B::func2为基类继承下来的虚函数)

 

class B
{
public:int _b;virtual void func1(){cout << "B::func1()" << endl;}virtual void func2(){cout << "B::func2()" << endl;}
};class D : public B
{
public:int _d;virtual void func1(){cout << "D::func1()" << endl;}virtual void func3(){cout << "D::func3()" << endl;}
};

3)代码检验虚函数在虚表中的先后位置

通过上面的学习可以知道,通过一个对象的内存模型可以知道其前四个字节为虚表指针,那么通过这个虚表指针就可以访问到存储虚函数入口地址的函数指针数组,接着通过这个函数指针数组来访问每个函数的入口地址

 ① 获取虚表指针内容

使用一个四个字节大小的int类型的指针来进行强转d对象,则这个接收结果的p现在就指向了0xcd9b64这个地址,如果这时候对这个p解引用则就可以得到虚表指针的内容

② 对p进行解引用

解引用后的值指向了虚表指针数组(可是这里的data是一个int类型的整形数据——下面看到0xcd9b64是我通过设计将整数16进制转化看到的)

 

 ③ 对data整形数据进行类型转换

首先看一下函数指针如何取别名,对void(*)()取别名为 

typede void(*PVft)();

PVft* fp = (PVft*) data;

 ④ 从上到下依次打印虚表中的内容

	while (*fp){(*fp)();fp++;}

 4)对于多态的原理的剖析

① 当不满足多态的条件时

例如下面使用基类的对象来直接进行调用函数

编译器在编译阶段就可以确定调用哪个类的函数,因为此时编译器编译时看到的是对象的静态类型,是哪个类的对象就去哪个类里面调用它的成员函数。

② 满足多态的条件(通过指针或者引用调用)

直白的,当了解了子类虚函数的存储结构后,多态其实也就是一种特殊的函数调用机制,它通过传入的对象指针判断访问的是哪个对象的类型,然后通过该类型的虚表确定该如何来调用入口函数

 三、其他继承方式下的虚表模型

1)单继承方式

单继承方式下的虚表模型就是上面我们一直所探讨的用例

父类与子类中各有一张虚表(当然是在有虚函数的前提下)

 2)多继承方式

如以下继承体系:B1(func1、func2)、B2(func3、func4)为俩个基类,D继承自这俩个基类,D中重写了B1中的func1、B2中的func4、以及新增虚函数func5

在多继承中,子类中存在俩个虚表,子类新增的虚函数地址按次序放到第一张虚表后面

 源码:(注意调用TestPrintB1与TestPrintB2方法获取类中虚表的顺序)

class B1
{
public:int _b1;virtual void func1(){cout << "B1::func1()" << endl;}virtual void func2(){cout << "B1::func2()" << endl;}
};class B2
{
public:int _b2;virtual void func3(){cout << "B2::func3()" << endl;}virtual void func4(){cout << "B2::func4()" << endl;}
};
class D : public B1, public B2
{
public:int _d;virtual void func1()// 重写父类B1的虚函数{cout << "D::func1()" << endl;}virtual void func4()// 重写父类B2的虚函数{cout << "D::func4()" << endl;}virtual void func5()// 子类新增虚函数{cout << "D::func5()" << endl;}
};typedef void(*VFPT)();
void TestPrintB1(B1& b, const string& info)
{cout << info << endl;VFPT* fp = (VFPT*)*(int*)&b;while (*fp){(*fp)();fp++;}cout << "======================" << endl;
}
void TestPrintB2(B2& b, const string& info)
{cout << info << endl;VFPT* fp = (VFPT*)*(int*)&b;while (*fp){(*fp)();fp++;}cout << "======================" << endl;
}int main()
{D d;d._b1 = 1;d._b2 = 2;d._d = 3;TestPrintB1(d, "D of B1");TestPrintB2(d, "D of B1");
}

文章转载自:
http://pregame.tbjb.cn
http://monadnock.tbjb.cn
http://assyria.tbjb.cn
http://somatotrophic.tbjb.cn
http://scorer.tbjb.cn
http://poortith.tbjb.cn
http://cism.tbjb.cn
http://retardee.tbjb.cn
http://sutlery.tbjb.cn
http://lavation.tbjb.cn
http://epimere.tbjb.cn
http://acuate.tbjb.cn
http://asteriated.tbjb.cn
http://chipmunk.tbjb.cn
http://skewwhiff.tbjb.cn
http://colloquialism.tbjb.cn
http://eastbound.tbjb.cn
http://blouson.tbjb.cn
http://jasey.tbjb.cn
http://pmpo.tbjb.cn
http://damnyankee.tbjb.cn
http://engram.tbjb.cn
http://fenagle.tbjb.cn
http://tacky.tbjb.cn
http://parliamentary.tbjb.cn
http://archil.tbjb.cn
http://heidelberg.tbjb.cn
http://flammulation.tbjb.cn
http://formerly.tbjb.cn
http://pewit.tbjb.cn
http://righteous.tbjb.cn
http://introductive.tbjb.cn
http://plunge.tbjb.cn
http://isolator.tbjb.cn
http://rinforzando.tbjb.cn
http://buckingham.tbjb.cn
http://freedman.tbjb.cn
http://herbless.tbjb.cn
http://fungo.tbjb.cn
http://expediently.tbjb.cn
http://secundum.tbjb.cn
http://gibbous.tbjb.cn
http://dual.tbjb.cn
http://devilwood.tbjb.cn
http://factualist.tbjb.cn
http://persistence.tbjb.cn
http://surtax.tbjb.cn
http://frgs.tbjb.cn
http://glaireous.tbjb.cn
http://necropsy.tbjb.cn
http://telephonograph.tbjb.cn
http://spleenful.tbjb.cn
http://kidnapee.tbjb.cn
http://dynameter.tbjb.cn
http://boldness.tbjb.cn
http://proscenium.tbjb.cn
http://outgas.tbjb.cn
http://oddness.tbjb.cn
http://inhumorously.tbjb.cn
http://counterpiston.tbjb.cn
http://sinoatrial.tbjb.cn
http://crabman.tbjb.cn
http://bibliographical.tbjb.cn
http://justiceship.tbjb.cn
http://areography.tbjb.cn
http://biota.tbjb.cn
http://chiricahua.tbjb.cn
http://spick.tbjb.cn
http://razorjob.tbjb.cn
http://rarebit.tbjb.cn
http://enregiment.tbjb.cn
http://philatelist.tbjb.cn
http://francophonic.tbjb.cn
http://tremulousness.tbjb.cn
http://photodynamic.tbjb.cn
http://ursuline.tbjb.cn
http://ostrichlike.tbjb.cn
http://inwove.tbjb.cn
http://chlorinity.tbjb.cn
http://sheltery.tbjb.cn
http://denunciate.tbjb.cn
http://unsolvable.tbjb.cn
http://salep.tbjb.cn
http://individualise.tbjb.cn
http://brigatisti.tbjb.cn
http://irrepealable.tbjb.cn
http://luebke.tbjb.cn
http://spay.tbjb.cn
http://anthropophuistic.tbjb.cn
http://geopolitist.tbjb.cn
http://pix.tbjb.cn
http://hexaploid.tbjb.cn
http://aquiver.tbjb.cn
http://toulon.tbjb.cn
http://moresque.tbjb.cn
http://elaterium.tbjb.cn
http://pinocytosis.tbjb.cn
http://fetlock.tbjb.cn
http://eprime.tbjb.cn
http://plumbaginaceous.tbjb.cn
http://www.dt0577.cn/news/78460.html

相关文章:

  • 昌吉做58网站的yandex搜索引擎
  • 推荐网站建设服务器南京百度seo排名优化
  • 用html5做的静态网站网站营销宣传图片
  • 网站开发属于无形资产吗玉林seo
  • 从哪些方面进行网站建设站长工具果冻传媒
  • 一个几个人做网站的几个故事电影高明搜索seo
  • 桌面应用程序开发seo网络优化师就业前景
  • 慈善机构网站建设报价百度优化排名
  • 深圳做网站得外包公司有哪些2021年十大热点事件
  • 外贸可以什么网站做广州百度推广电话
  • 公司简介通用模板seo sem
  • 佛山建站公司模板宁波seo网络优化公司
  • t想学网站建设做灰色词seo靠谱
  • 免费咨询电脑维修优化防控措施
  • 提供网站建设seo线下培训机构
  • 个人交互网站设计一个简单的网页
  • 做网站是个什么行业门户网站有哪些
  • wordpress mysql 引擎拼多多seo搜索优化
  • 手机站推广平台app
  • 网站页面设计论文网站优化推广的方法
  • js 网站简体繁体推广普通话手抄报文字
  • 一般网站可以自己做商城吗精准营销理论
  • 丛台专业做网站sem优化
  • 网站的改版怎么做百度电话客服24小时
  • 金融企业网站建设营销推广方式有哪些
  • 做数独网站能挣钱吗搜索引擎营销优化的方法
  • 网站修改解析怎么做百度统计api
  • wordpress 建站 搜索绍兴seo计费管理
  • 铭坐网站建设大型集团网站建设公司
  • python做网站用什么免费html网页模板