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

免费设计房屋的网站网站如何添加百度统计

免费设计房屋的网站,网站如何添加百度统计,瑞安建设网站,公众号取名简单大气文章目录 1. 多态的概念和实现1.1 概念1.2 实现1.2.1 协变1.2.2 析构函数1.2.3 子类虚函数不加virtual 2. C11 final和override3.1 final3.2 override 3. 函数重载、重写与隐藏4. 多态的原理5. 抽象类6.单继承和多继承的虚表6.1 单继承6.2 多继承 7. 菱形继承的虚表(了解)7.1 菱…

文章目录

  • 1. 多态的概念和实现
    • 1.1 概念
    • 1.2 实现
      • 1.2.1 协变
      • 1.2.2 析构函数
      • 1.2.3 子类虚函数不加`virtual`
  • 2. C++11 `final`和`override`
    • 3.1 `final`
    • 3.2 `override`
  • 3. 函数重载、重写与隐藏
  • 4. 多态的原理
  • 5. 抽象类
  • 6.单继承和多继承的虚表
    • 6.1 单继承
    • 6.2 多继承
  • 7. 菱形继承的虚表(了解)
    • 7.1 菱形继承
    • 7.2 菱形虚拟继承
  • 8. 多态面试题

在这里插入图片描述

1. 多态的概念和实现


1.1 概念

面向对象语言三大特性之一:多态,意思是多种形态,当不同的对象去做同一件事时会有不同的状态/结果

1.2 实现

多态要在继承的关系中实现,需要满足2个条件:

  1. 子类必须完成父类虚函数的重写
  2. 必须通过父类的指针/引用去调用虚函数

在这里插入图片描述

virtual修饰的成员函数叫做虚函数

子类对父类虚函数的重写需要满足三同,即函数名、返回值、参数类型相同,但有三种情况例外

  1. 协变:返回值可以是其他父子类或自身的指针/引用
  2. 析构函数
  3. 子类重写父类虚函数时可以不加virtual

我们分别对这三点做解释

1.2.1 协变

父子类的返回值可以不相同,但必须是其他父子类后者自身类的指针/引用

在这里插入图片描述

1.2.2 析构函数

在继承的章节,我们说析构函数名被统一处理为destructor(),但没说具体原因,其实是要对析构函数设计多态的原因

在这里插入图片描述

在上面的场景中,ptr1和ptr2分别指向动态开辟出来的A对象和B对象;B对象中的一个成员,指向动态开辟出来的内存;将来我们要手动释放ptr1和ptr2指向的内存,于是使用delete ptr1和delete ptr2,但根据结果,没能释放掉B对象,于是导致了内存泄漏的问题

我们希望的是指针指向哪个对象,就delete哪个对象的析构,这就要求我们对析构函数实现多态调用,而多态调用要满足三同,其中函数名已经不满足了,于是编译器就将父子类的析构函数重命名为destructor(),只要我们将析构函数定义为虚函数,就满足多态了

因此,父子类的析构函数推荐加上virtual

在这里插入图片描述

1.2.3 子类虚函数不加virtual

在这里插入图片描述

可以看到,子类虚函数可以不加virtual修饰,此时BuyTicket函数也满足多态,这是因为重写的本质是对父类虚函数实现的重写;用一道例题来更好的理解这点

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()
{B* p = new B;p->test();return 0;
}
// A: A->0 B: B->1 C: A->1 D: B->0 E: 编译出错 F: 以上都不正确

在这里插入图片描述

2. C++11 finaloverride


3.1 final

如果希望一个类不能被继承,有两种方式:

  1. 将类的构造函数私有化,这是C++98的做法
  2. 将类进行final修饰,被修饰的类叫做最总类,这是C++11的做法

在这里插入图片描述

3.2 override

override关键字用于检查子类的虚函数是否完成父类虚函数的重写

在这里插入图片描述

3. 函数重载、重写与隐藏


在这里插入图片描述

4. 多态的原理


在这里插入图片描述

上述代码的结果出乎我们的意料,为什么A对象的大小是12字节?经过调试,我们发现A对象中多了一个指针_vfptr

直接给出结论,如果类中有虚函数,那么该类实例化出的对象都要有一个指针,我们把该指针称为虚表指针(在构造函数初始化列表中初始化);该指针指向一个虚表,虚表是一个函数指针数组,存放着虚函数的地址

子类对象会将父类的虚函数拷贝到自己的虚表中,并检查是否完成虚函数的重写,如果完成,将虚函数覆盖为自己的虚函数,当使用父类的引用/指针去调用虚函数时,由于发生切片,如果指向父类,去调用父类的虚函数,如果指向子类,去调用子类中父类部分的虚函数,这就是多态的原理

在这里插入图片描述

多态调用和正常调用区别:当进行编译时,编译器会检查函数是否满足多态,如果满足,那么会在执行代码时去对象的虚表中找虚函数调用,如果不满足,那么在编译时就已经确定要调用函数的地址

在这里要分清楚几个概念:

  1. 虚函数不在虚表中,虚表中存放的是虚函数的地址,虚函数存放在常量区(代码段)上
  2. 虚表存放在常量区上,下面有代码验证
  3. 虚基表是继承中存放虚基类偏移量的,用来解决菱形继承数据冗余和二义性的问题

在这里插入图片描述

5. 抽象类


在这里插入图片描述

在虚函数后加上 =0,表示该虚函数是纯虚函数,有纯虚函数的类叫做抽象类

抽象类在现实生活中没有对应的实体,因此无法实例化出对象;继承抽象类的子类同样也无法实例化出对象,这就强制要求我们完成父类虚函数的重写

在这里插入图片描述

6.单继承和多继承的虚表


6.1 单继承

在这里插入图片描述

运行上述代码,对比监视窗口和内存窗口,父类的func1和func2都继承了下来,重写了func1,于是将父类的func1覆盖;子类自身的虚函数直接往父类部分的虚表中放,监视窗口没显示func3和func4是因为vs监视窗口的设计问题,在内存中是能看到还有两个指针,这两个指针指向的就是func3和func4,用一份代码来证明

在这里插入图片描述

6.2 多继承

在这里插入图片描述

在多继承中,子类中有两个虚表指针,分别在A类的部分和B类的部分中,A类的部分继承A类的虚函数,B类的部分继承B类的虚函数,再看是否完成重写,有就拿自身的覆盖;自身的虚函数默认往先继承类的虚表中放

在这里插入图片描述

为什么要有多继承对象要有两张虚表,不能把所有的虚函数放在一张虚表中吗?有这样的场景,分别有两个父类的指针指向同一个子类对象,通过任何一个父类指针都应该调用子类的虚函数,但如果只有一张虚表,就变成只有其中一个父类指针能调用子类的虚函数

在这里插入图片描述

7. 菱形继承的虚表(了解)


7.1 菱形继承

在这里插入图片描述

在这里插入图片描述

7.2 菱形虚拟继承

在这里插入图片描述

在这里插入图片描述

8. 多态面试题


class A 
{
public:A(const char* s){ cout << s << endl; }
};class B :virtual public A
{
public:B(const char* s1,const char* s2) :A(s1) { cout << s2 << endl; }
};
class C :virtual public A
{
public:C(const char* s1, const char* s2):A(s1) { cout << s2 << endl; }
};class D :public B, public C
{
public:D(const char* s1, const char* s2, const char* s3, const char* s4):B(s1, s2),C(s1, s3),A(s1){cout << s4 << endl;}
};int main()
{D* p = new D("class A", "class B", "class C", "class D");delete p;return 0;
}// A:class A class B class C class D 
// B:class D class B class C class A
// C:class D class C class B class A 
// D:class A class C class B class D// 答案:A

由此可以证明:初始化列表的初始化顺序是按变量在内存中声明的顺序或类在内存中继承的顺序(先继承的类先初始化);同时同一个对象中,同一个类只会初始化一次

  1. inline函数可以是虚函数吗?

    可以,但是编译器会忽略inline属性,因为虚函数要放到虚表中

  2. 静态成员函数可以是虚函数吗?

    不可以,静态成员函数属于整个类,无论是通过父类或子类调用,调用的都是同一个静态成员函数;静态成员函数在编译时就已经确定地址,而虚函数要到运行时去虚函数表中找

  3. 构造函数可以是虚函数吗?

    不可以,虚表指针在构造函数的初始化列表中初始化,如果构造函数时虚函数,虚表指针就无法初始化了

  4. 对象访问普通函数快还是虚函数快?

    如果是普通对象,一样快;如果是对象的指针/引用且满足多态,则调用普通函数快,调用虚函数需要在虚表中找

  5. 虚函数表在什么阶段生成?存在哪里?

    虚函数表在编译阶段生成,存放在常量区

http://www.yayakq.cn/news/355/

相关文章:

  • 做网站时已做好了ps怎么倒入ks2e做网站
  • 网站电脑版和手机版区别聚名网域名转出
  • 四川省示范校建设网站电子工程建设网
  • wap手机网站 作用国内域名购买网站
  • 详述网站建设的过程简答题简述电子商务网站建设的过程
  • 天塔网站建设公司海城 网站建设
  • 上海传媒公司ceo是谁郑州网站seo多少钱
  • 事业单位网站建设计划中小企业网站建设 论文
  • 做的好看的旅游网站聊天app开发报价单
  • 如何知道一个网站做的什么推广网站建设五合一
  • 单招网站开发创建团购网站
  • 规划营销型网站结构海航科技网站建设
  • 推进网站建设工作计划做网站和做公众号
  • 东莞高端网站建设费用做品牌设计网站
  • 云服务器网站解析深圳市测绘建设局网站
  • 小米路由HD可以做网站吗ai自动设计logo
  • 在线设计海报的网站软文范例大全100字
  • 前端网站开发流程南京网站优化平台
  • 西安 网站 公司免费的行情网站
  • 做网站公司还有没有活路注册公司条件和要求
  • 梅州哪里做网站网络有限公司经营范围
  • 不动产登记门户网站建设方案品牌注册公司
  • 南坪网站建设哪里好企业网站开发报价
  • wordpress 子站点提供网站建设框架
  • 郑州建立一个网站需要哪些互联网推广是什么意思
  • 网站建设通报淘宝运营培训班
  • 建设银行网站链接石家庄做网站的公司
  • 做网站有哪些好公司建设网站聊天室
  • wordpress 微信关注插件郑州众志seo
  • 如何提高网站访客数济南优化网络营销