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

重庆网站建设公司的网站跨境o2o网站建设方案

重庆网站建设公司的网站,跨境o2o网站建设方案,wordpress滑块,中国最好的室内设计网目录 1.多态的概念 2.多态的实现 3.虚函数 虚函数的重写 题目练习 协变 析构函数的重写 重载重写隐藏 3.纯虚函数和抽象类 4.多态的原理 1.虚表 2.虚函数指针 总结: 1.多态的概念 说人话就是在继承的基础上传不同的对象实现不同的功能。 多态分为静态多…

目录

1.多态的概念

2.多态的实现

3.虚函数

虚函数的重写

题目练习

协变

析构函数的重写

重载重写隐藏

3.纯虚函数和抽象类

4.多态的原理

1.虚表

2.虚函数指针

总结:


1.多态的概念

   说人话就是在继承的基础上传不同的对象实现不同的功能。

多态分为静态多态和动态多态,静态多态又称编译时多态,就是编译时就确定调用哪个函数,例如函数重载传不同的参数调用不同的函数这在编译时就是确定的,动态多态又称运行时多态,就是在运行时根据实际对象才决定调用哪个函数。

2.多态的实现

1.必须是基类的指针或引用调用的虚函数。

2.被调用的虚函数完成了重写。

下面代码打印的是B的fun()。就是满足了多态的两个实现条件。

那么我们要反问一句为什么要必须调用基类的指针或引用呢?赋值不行吗?答案是不行,因为前面继承中我们学习过派生类给基类赋值会发生切片,直接把派生类部分给切掉然后进行拷贝构造进行赋值,无法调用派生类f()。

我们现在记住一句话叫做是根据对象的实际类型进行多态函数的调用。我们传引用它的类型还是派生类只不过我们不能访问派生类的派生类新增部分,但是如果我们去传值进行拷贝构造的话,它的类型就是基类而不再是派生类。

 

class A {
public:virtual void f() {cout << "A::f()" << endl;}
};class B : public A 
{
private:virtual void f() override {cout << "B::f()" << endl;}
};int main() {A* a = new B;a->f();return 0;
}

3.虚函数

下面我们来了解多态的实现的重要工具虚函数,在函数前面加virtual就是虚函数,它的作用就是来实现多态。

虚函数的重写

当派生类与父类的成员函数有同名时,该成员函数构成隐藏,当父类和父类的成员函数,它们的函数名相同,并且参数类型相同,返回值相同时,并且它们都是虚函数时啊,这时我们就构成了虚函数的重写。父类的虚函数是一个实现方式,子类的虚函数是一个实现方式,虚函数的复写是我们实现传不同对象调用不同函数的关键。

注意:正常情况下,我们父类和子类的虚函数都要加virtual,但是实际上,如果我们父类加虚函数关键字,子类不加,它仍然能够复写,但是如果父类没加虚函数关键字,但是子类加了,它就不能构成复写,这里是一个比较特殊的点。

题目练习

这个题目我们可以看出它是通过B类型的指针去调用test,B的test是从A中继承的,这时调用test又会调用func,但是它构成了多态所以我们调用B类的func,但是,这里重写仅仅是实现的重写,但是val仍然是父类的val。所以这道题选B,非常的坑。

以下程序输出结果是什么()
A: A->0 B: B->1 C: A->1 D: B->0 E: 编译出错 F: 以上都不正确
class A
{
public:
virtual void func(int val = 1){ std::cout<<"A->"<< val <<std::endl;}
virtual void test(){ func();}
};
class B : public A
{
public:
void func(int val = 0){ std::cout<<"B->"<< val <<std::endl; }
};
int main(int argc ,char* argv[])
{
B*p = new B;p->test();
return 0;
}

协变

派⽣类重写基类虚函数时,与基类虚函数返回值类型不同。即基类虚函数返回基类对象的指针或引
⽤,派⽣类虚函数返回派⽣类对象的指针或者引⽤时,称为协变。协变的实际意义并不⼤,所以们
了解⼀下即可。

析构函数的重写

在继承中虚构函数要进行重写,我们要对析构函数进行谨慎处理,核心问题在于:

当通过 基类指针删除派生类对象 时,如果基类的析构函数 不是虚函数,会导致:

  • 派生类的析构函数不被调用,仅调用基类的析构函数。

  • 派生类独有的资源(如动态内存、文件句柄)泄漏

下面我们用代码来解释一下。

如果我们不写析构函数的虚函数的话,它析构只会调用A的析构。核心问题再次强调一下:基类指针删除派生类对象,不写析构不会调派生类的析构。

using namespace std;class A {
public:virtual void f() {cout << "A::f()" << endl;}virtual ~A(){cout << "~A";}
};class B : public A 
{
private:virtual void f() override {cout << "B::f()" << endl;}virtual ~B(){cout << "~B";}
};int main() {A* a = new A;A* b = new B;delete a;delete b;return 0;
}

了解完析构函数继承要写多态后,有的人就要问了,主播主播构造函数和静态函数需不需要写呢?

这个问题我们下面来解答会更清晰一点!

重载重写隐藏

重载是在同一作用域内,函数名相同参数不同的函数构成重载,根据不同的参数进行调用。

重写是在不同作用域父类和子类同名,同参数,同返回值的虚函数(函数名前加virtual)进行传不同的对象调用不同的函数实现多态。

隐藏是在不同作用域,父类和子类成员同名父类成员在派生类中会被隐藏。

3.纯虚函数和抽象类

在虚函数后加=0构成纯虚函数,它没有实际的定义。包含纯虚函数的类叫抽象类。抽象类不能实例化出对象,派生类如果继承后不重写纯虚函数也会是抽象类。纯虚函数某种程度上强制了派生类重写虚函数,因为不重写的话还是抽象类,无法实例化出对象。

了解完多态的定义和概念后,我们下来了解多态的原理。

4.多态的原理

多态是依赖虚表和虚指针来实现的。

1.虚表

每个包含虚函数的类都含有一个虚表,存储虚函数的地址。

当派生类继承含义虚函数的父类时,如果派生类不重写虚函数,它的虚表的内容和父类的虚表内容一致,只不过会新增派生类中新增的虚函数。如果派生类重写父类的虚函数,重写的虚函数就会覆盖原有的父类的虚函数。

注意:即使派生类中不重写父类的虚函数,它的vptr指向的物理地址也不一样。一个类共享一个vptr。

虚函数表细则:

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

2.虚函数指针

每个含有虚函数的类中有虚函数指针,指向虚函数表,我们通过这个指针来调用虚函数。

结合下图我们再结合我们继承的知识,我们来复盘一下虚函数调用的具体过程,__vfptr是指向虚表的指针,虚表里存储的虚函数的地址,如果我们父类含有虚函数,子类不对它进行重写,子类依旧会继承父类的虚函数并有自己独特的虚函数表,只不过它的定义和父类相同,如果我们对父类的虚函数进行重写,那么我们重写的虚函数会覆盖原有的虚函数。这样我们就可以调用重写的虚函数了。

当我们把派生类对象的引用或地址传给父类的引用或地址时,它不会发生切片,仅仅是我们不能通过它访问派生类新增的对象,但是__vfptr是可以访问的。且我们访问的是修改之后的__vfptr,我们借助代码再来理解一下。

“派生类对象会拥有自己的 __vfptr,它默认指向派生类的虚表。如果派生类重写了基类的虚函数,则虚表中对应条目会更新为派生类的函数地址;否则保留基类的实现。

注意:这里的虚表都是独立的并不是基类的虚表和派生类的虚表共享一份,他们之间是独立的独立的独立的!!!

再借鉴下面这句话来理解一下,

派⽣类由两部分构成,继承下来的基类和⾃⼰的成员,⼀般情况下,继承下来的基类中有虚函数表
指针,⾃⼰就不会再⽣成虚函数表指针。但是要注意的这⾥继承下来的基类部分虚函数表指针和基
类对象的虚函数表指针不是同⼀个,就像基类对象的成员和派⽣类对象中的基类对象成员也独⽴
的。

这里就是虚函数的调用是根据其实际类型进行调用的。

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

总结:

相信到了这里大家就该大致了解多态和继承了,继承的基础上我们定义了多态来实现编程的方便,继承是父类的成员继承给派生类,但是它们之间的成员并没有关联,父类有int a,派生类继承int a,派生类中的a和父类的a实际是没有关系的,因为本质上它们是属于两个不同的类,多态我们引入了虚函数指针和虚函数表,虚函数表中的虚函数继承了父类的虚函数,如果我们再派生类中对他们进行重写,重写的虚函数就会覆盖原有的虚函数表中对应的虚函数。

附言:上文中我们提到了构造函数和静态函数不可以虚函数化,现在我们可以给出解释,构造函数不可以虚函数化是因为函数前面加virtual会调用虚函数指针,但是虚函数指针是构造中生成的,这会发生矛盾,编译无法通过,至于静态函数不可以虚函数化,静态函数不属于某个类的对象,它是属于整个类,它不通过对象调用,没有this指针,前面我们说过多态就是根据不同的对象调用来实现多态,但是静态函数不通过对象调用,所以我们的静态函数不可以虚函数化!!!

如有错误,请指正,博主多有感谢!!!


文章转载自:

http://rLXsk0Zv.rgwrL.cn
http://CL3M6wnb.rgwrL.cn
http://UAKLMsbA.rgwrL.cn
http://bKPDTzag.rgwrL.cn
http://bcEkr5yW.rgwrL.cn
http://bI17xCng.rgwrL.cn
http://Q8dgVGiR.rgwrL.cn
http://ERQzscEy.rgwrL.cn
http://1s8SlNon.rgwrL.cn
http://1AIiOre8.rgwrL.cn
http://gfHROl32.rgwrL.cn
http://YZ1hTwQL.rgwrL.cn
http://evQ2SpUt.rgwrL.cn
http://o8iC6DIO.rgwrL.cn
http://U1pfrt4s.rgwrL.cn
http://GrTbXYha.rgwrL.cn
http://RmaH3Xl4.rgwrL.cn
http://b3rkL856.rgwrL.cn
http://rKUPEFTt.rgwrL.cn
http://p2Npy0uT.rgwrL.cn
http://qZHwLGKW.rgwrL.cn
http://uuAtDet0.rgwrL.cn
http://Hj19lr5j.rgwrL.cn
http://8O4u5ivL.rgwrL.cn
http://tToAgg8D.rgwrL.cn
http://RPlCtdQi.rgwrL.cn
http://vJGCTswc.rgwrL.cn
http://v73S8DLQ.rgwrL.cn
http://Z3aQxdGj.rgwrL.cn
http://3hjV1sJs.rgwrL.cn
http://www.dtcms.com/wzjs/609145.html

相关文章:

  • 生成flash的网站源码中文安卓开发工具
  • 汕头如何建设网站设计如何让网页适应屏幕尺寸
  • 手机网站 侧边栏导航网站滑动
  • 有没有专业做挂的网站吗北京附近做网站的公司有哪些
  • 邢台 网站建设建立什么填词语
  • 怎么自己做淘宝客网站ui培训学校哪家好
  • 电子商务网站策划书3000字城市之星福州网站建设
  • 整容网站模板wordpress如何修改背景图片
  • 昆明做网站win主机安装wordpress
  • 天津电子商务网站建设南阳平面设计培训学校
  • 社交网站 设计高级搜索引擎
  • 网络游戏公司排行榜前十名云南seo网站关键词优化软件
  • 在线做六级阅读网站徐州手机网站开发公司电话
  • o2o网站建设方案讲解如何做网站关键词词霸
  • 自学免费网站建设自己做的网站别人怎么访问
  • 基于网站开发app建设卒中中心几个网站
  • 网站必须备案吗营销型网站建设主要步骤
  • html5网站开发公司做网站大概要多久
  • 如何使用wordpress建站做视频网站需要什么服务器配置
  • 婚纱摄影网站的设计与实现论文万网是做什么的
  • 珠海网站上排名写一个app多少钱
  • 徐州网站建设技术全flash网站制作教程
  • 深圳做网站排名公司哪家好古腾堡布局的网站
  • 嘉兴外贸网站建设网站地图建设有什么用
  • 怎么建设宣传网站wordpress打开网站前动画
  • 果壳 wordpressseo还有前景吗
  • 什么是品牌网站报名系统网站开发
  • 做吗查网站的流量亚马逊跨境电商官方网站
  • 数字化校园门户网站建设方案页面设计图标
  • 河北建设厅官网站首页手机兼职有哪些