四、2023.9.30.C++面向对象end.4

文章目录

  • 49、 简述一下什么是常函数,有什么作用?
  • 50、 说说什么是虚继承,解决什么问题,如何实现?
  • 51、简述一下虚函数和纯虚函数,以及实现原理?
  • 52、说说纯虚函数能实例化吗,为什么?派生类要实现吗,为什么?
  • 53、说说C++中虚函数与纯虚函数的区别?
  • 54、说说 C++ 中什么是菱形继承问题,如何解决?
  • 55、请问构造函数中的能不能调用虚方法?
  • 56、请问拷贝构造函数的参数是什么传递方式,为什么?
  • 57、如何理解抽象类?
  • 58、什么是多态?除了虚函数,还有什么方式能实现多态?
  • 59、简述一下虚析构函数,什么作用?
  • 60、说说什么是虚基类,可否被实例化?
  • 61、简述一下拷贝赋值和移动赋值?
  • 62、仿函数了解吗?有什么作用?
  • 62、C++ 中哪些函数不能被声明为虚函数?

49、 简述一下什么是常函数,有什么作用?

类的成员函数后面加 const,表明这个函数不会对这个类对象的数据成员(准确地说是非静态数据成员)作任何改变
在设计类的时候,一个原则就是对于不改变数据成员的成员函数都要在后面加const,而对于改变数据成员的成员函数不能加 const。所以 const 关键字对成员函数的行为作了更明确的限定:有 const 修饰的成员函数(指 const 放在函数参数表的后面,而不是在函数前面或者参数表内),只能读取数据成员,不能改变数据成员
没有 const 修饰的成员函数,对数据成员则是可读可写的。除此之外,在类的成员函数后面加 const 还有什么好处呢?那就是常量(即 const)对象可以调用 const成员函数,而不能调用非const修饰的函数。正如非const类型的数据可以给const类型的变量赋值一样,反之则不成立。

#include<iostream>
using namespace std;
class CStu {
public:int a;CStu() {a = 12;
}
void Show() const {
//a = 13; //常函数不能修改数据成员cout <<a << "I am show()" << endl;}
};
int main() {CStu st;st.Show();system("pause");return 0;
}

50、 说说什么是虚继承,解决什么问题,如何实现?

虚继承是解决C++多重继承问题的一种手段,从不同途径继承来的同一基类,会在子类中存在多份拷贝。这将存在两个问题:

  • 其一,浪费存储空间;
  • 第二,存在二义性问题,通常可以将派生类对象的地址赋值给基类对象,实现的具体方式是,将基类指针指向继承类(继承类有基类的拷贝)中的基类对象的地址,但是多重继承可能存在一个基类的多份拷贝,这就出现了二义性。虚继承可以解决多种继承前面提到的两个问题。

51、简述一下虚函数和纯虚函数,以及实现原理?

(一)虚函数

  1. C++中的虚函数的作用主要是实现了多态的机制。
  2. 关于多态,简而言之就是用父类型的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”,这是一种泛型技术。
  3. 如果调用非虚函数,则无论实际对象是什么类型,都执行基类类型所定义的函数。非虚函数总是在编译时根据调用该函数的对象,引用或指针的类型而确定。如果调用虚函数,则直到运行时才能确定调用哪个函数,运行的虚函数是引用所绑定或指针所指向的对象所属类型定义的版本。虚函数必须是基类的非静态成员函数。
  4. 虚函数的作用是实现动态联编,也就是在程序的运行阶段动态地选择合适的成员函数,在定义了虚函数后,可以在基类的派生类中对虚函数重新定义,在派生类中重新定义的函数应与虚函数具有相同的形参个数和形参类型。以实现统一的接口,不同定义过程。如果在派生类中没有对虚函数重新定义,则它继承其基类的虚函数。
    在这里插入图片描述
class Person{
public://虚函数virtual void GetName(){cout<<"PersonName:xiaosi"<<endl;};
};
class Student:public Person{
public:void GetName(){cout<<"StudentName:xiaosi"<<endl;};
};
int main(){
//指针Person *person = new Student();
//基类调用子类的函数person->GetName();//StudentName:xiaosi
}

虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的。简称为V-Table。在
这个表中,主是要一个类的虚函数的地址表,这张表解决了继承、覆盖的问题,保证其容真实反应实际的函数。这样,在有虚函数的类的实例中这个表被分配在了这个实例的内存中,所以,当我们用父类的指针来操作一个子类的时候,这张虚函数表就显得由为重要了,它就像一个地图一样,指明了实际所应该调用的函数。

(二)纯虚函数
纯虚函数是在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现的实现方法。
在基类中实现纯虚函数的方法是在函数原型后加“=0” virtualvoid GetName() =0。在很多情
况下,基类本身生成对象是不合情理的。例如,动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理。为了解决上述问题,将函数定义为纯虚函数,则编译器要求在派生类中必须予以重写以实现多态性。
同时含有纯虚拟函数的类称为抽象类,它不能生成对象。这样就很好地解决了上述两个问题。将函数定义为纯虚函数能够说明,该函数为后代类型提供了可以覆盖的接口,但是这个类中的函数绝不会调用。
声明了纯虚函数的类是一个抽象类。

所以,用户不能创建类的实例,只能创建它的派生类的实例。必须在继承类中重新声明函数(不要后面的=0)否则该派生类也不能实例化,而且它们在抽象类中往往没有定义。定义纯虚函数的目的在于,使派生类仅仅只是继承函数的接口。纯虚函数的意义,让所有的类对象(主要是派生类对象)都可以执行纯虚函数的动作,但类无法为纯虚函数提供一个合理的缺省实现。所以类纯虚函数的声明就是在告诉子类的设计者,“你必须提供一个纯虚函数的实现,但我不知道你会怎样实现它”。

//抽象类
class Person{
public://纯虚函数virtual void GetName()=0;
};
class Student:public Person{
public:Student(){
};
void GetName(){cout<<"StudentName:xiaosi"<<endl;};
};
int main(){Student student;
}

52、说说纯虚函数能实例化吗,为什么?派生类要实现吗,为什么?

  1. 纯虚函数不可以实例化,但是可以用其派生类实例化,示例如下:
class Base
{
public:
virtual void func() = 0;
};
#include<iostream>
using namespace std;
class Base {
public:virtual void func() = 0;
};
class Derived :public Base
{
public:void func() override {cout << "哈哈" << endl;
}
};
int main() {Base *b = new Derived();b->func();return 0;
}
  1. 虚函数的原理采用 vtable。类中含有纯虚函数时,其vtable 不完全,有个空位。
    即“纯虚函数在类的vftable表中对应的表项被赋值为0。也就是指向一个不存在的函数。由于编译器绝对不允许有调用一个不存在的函数的可能,所以该类不能生成对象。在它的派生类中,除非重写此函数,否则也不能生成对象。”所以纯虚函数不能实例化。
  2. 纯虚函数是在基类中声明的虚函数,它要求任何派生类都要定义自己的实现方法,以实现多态性。
  3. 定义纯虚函数是为了实现一个接口,用来规范派生类的行为,也即规范继承这个类的程序员必须实现这个函数。派生类仅仅只是继承函数的接口。纯虚函数的意义在于,让所有的类对象(主要是派生类对象)都可以执行纯虚函数的动作,但基类无法为纯虚函数提供一个合理的缺省实现。所以类纯虚函数的声明就是在告诉子类的设计者,“你必须提供一个纯虚函数的实现,但我不知道你会怎样实现它”。

53、说说C++中虚函数与纯虚函数的区别?

  1. 虚函数和纯虚函数可以定义在同一个类中,含有纯虚函数的类被称为抽象类,而只含有虚函数的类不能被称为抽象类
  2. 虚函数可以被直接使用,也可以被子类重载以后,以多态的形式调用,而纯虚函数必须在子类中实现该函数才可以使用,因为纯虚函数在基类有声明而没有定义。
  3. 虚函数和纯虚函数都可以在子类中被重载,以多态的形式被调用。
  4. 虚函数和纯虚函数通常存在于抽象基类之中,被继承的子类重载,目的是提供一个统一的接口
  5. 虚函数的定义形式: virtual{} ;纯虚函数的定义形式: virtual { } = 0 ;在虚函数和纯虚函数
    的定义中不能有static标识符,原因很简单,被static修饰的函数在编译时要求前期绑定,然而虚函数却是动态绑定,而且被两者修饰的函数生命周期也不一样。

54、说说 C++ 中什么是菱形继承问题,如何解决?

导致问题:菱形继承会导致数据重复和产生歧义;
解决办法:使用虚继承,可确保每份数据自继承一次;

55、请问构造函数中的能不能调用虚方法?

  • 不要在构造函数中调用虚方法,从语法上讲,调用完全没有问题,但是从效果上看,往往不能达到需要的目的。
  • 派生类对象构造期间进入基类的构造函数时,对象类型变成了基类类型,而不是派生类类型。
  • 同样,进入基类析构函数时,对象也是基类类型。
    所以,虚函数始终仅仅调用基类的虚函数(如果是基类调用虚函数),不能达到多态的效果,所以放在构造函数中是没有意义的,而且往往不能达到本来想要的效果。

56、请问拷贝构造函数的参数是什么传递方式,为什么?

  1. 拷贝构造函数的参数必须使用引用传递
  2. 如果拷贝构造函数中的参数不是一个引用,即形如CClass(const CClass c_class),那么就相当于采用了传值的方式(pass-by-value),而传值的方式会调用该类的拷贝构造函数,从而造成无穷递归地调用拷贝构造函数。因此拷贝构造函数的参数必须是一个引用。需要澄清的是,传指针其实也是传值,如果上面的拷贝构造函数写成CClass(const CClass*c_class),也是不行的。事实上,只有传引用不是传值外,其他所有的传递方式都是传值。

57、如何理解抽象类?

  1. 抽象类的定义如下:
    纯虚函数是在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。在基类中实现纯虚函数的方法是在函数原型后加“=0”,有虚函数的类就叫做抽象类。
  2. 抽象类有如下几个特点:
    1)抽象类只能用作其他类的基类,不能建立抽象类对象。
    2)抽象类不能用作参数类型、函数返回类型或显式转换的类型。
    3)可以定义指向抽象类的指针和引用,此指针可以指向它的派生类,进而实现多态性。

58、什么是多态?除了虚函数,还有什么方式能实现多态?

  1. 多态是面向对象的重要特性之一,它是一种行为的封装,就是不同对象对同一行为会有不同的状态。(举例 : 学生和成人都去买票时,学生会打折,成人不会)
  2. 多态是以封装和继承为基础的。在C++中多态分为静态多态(早绑定)和动态多态(晚绑定)两种,其中动态多态是通过虚函数实现,静态多态通过函数重载实现,代码如下:

59、简述一下虚析构函数,什么作用?

  1. 虚析构函数,是将基类的析构函数声明为virtual,举例如下:
class TimeKeeper {public:TimeKeeper() {}virtual ~TimeKeeper() {}
};
  1. 虚析构函数的主要作用是防止内存泄露。

定义一个基类的指针p,在delete p时,如果基类的析构函数是虚函数,这时只会看p所赋值的对
象,如果p赋值的对象是派生类的对象,就会调用派生类的析构函数(毫无疑问,在这之前也会先
调用基类的构造函数,在调用派生类的构造函数,然后调用派生类的析构函数,基类的析构函数,所谓先构造的后释放)
;如果p赋值的对象是基类的对象,就会调用基类的析构函数,这样就不会造成内存泄露。
如果基类的析构函数不是虚函数,在delete p时,调用析构函数时,只会看指针的数据类型,而不会去看赋值的对象,这样就会造成内存泄露。

60、说说什么是虚基类,可否被实例化?

  1. 在被继承的类前面加上virtual关键字,这时被继承的类称为虚基类,代码如下:
class A
class B1:public virtual A;
class B2:public virtual A;
class D:public B1,public B2;
  1. 虚继承的类可以被实例化,举例如下:

61、简述一下拷贝赋值和移动赋值?

  1. 拷贝赋值是通过拷贝构造函数来赋值,在创建对象时,使用同一类中之前创建的对象来初始化新创
    建的对象。
  2. 移动赋值是通过移动构造函数来赋值,二者的主要区别在于
    1)拷贝构造函数的形参是一个左值引用,而移动构造函数的形参是一个右值引用;
    2)拷贝构造函数完成的是整个对象或变量的拷贝,而移动构造函数是生成一个指针指向源对象或
    变量的地址,接管源对象的内存,相对于大量数据的拷贝节省时间和内存空间。

62、仿函数了解吗?有什么作用?

  1. 仿函数(functor)又称为函数对象(function object)是一个能行使函数功能的类。仿函数的语
    法几乎和我们普通的函数调用一样,不过作为仿函数的类,都必须重载operator()运算符,举个例
    子:
class Func{
public:void operator() (const string& str) const {cout<<str<<endl;}
};Func myFunc;myFunc("helloworld!");
>>>helloworld!

62、C++ 中哪些函数不能被声明为虚函数?

常见的不不能声明为虚函数的有:普通函数(非成员函数),静态成员函数,内联成员函数,构造函数,友元函数。

谁懂啊…
虚函数 虚析构函数 虚表指针 虚基类 纯虚函数 虚函数表 虚构造函数 虚继承 虚继承的类
你们虚氏家族太狠了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/91922.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【数据结构与算法】通过双向链表和HashMap实现LRU缓存 详解

这个双向链表采用的是有伪头节点和伪尾节点的 与上一篇文章中单链表的实现不同&#xff0c;区别于在实例化这个链表时就初始化了的伪头节点和伪尾节点&#xff0c;并相互指向&#xff0c;在第一次添加节点时&#xff0c;不需要再考虑空指针指向问题了。 /*** 通过链表与HashMa…

1 论文笔记:Efficient Trajectory Similarity Computation with ContrastiveLearning

2022CIKM 1 intro 1.1 背景 轨迹相似度计算是轨迹分析任务&#xff08;相似子轨迹搜索、轨迹预测和轨迹聚类&#xff09;最基础的组件之一现有的关于轨迹相似度计算的研究主要可以分为两大类&#xff1a; 传统方法 DTW、EDR、EDwP等二次计算复杂度O(n^2)缺乏稳健性 会受到非…

Flutter笔记:滚动之-无限滚动与动态加载的实现(GetX简单状态管理版)

Flutter笔记 无限滚动与动态加载的实现&#xff08;GeX简单状态管理版&#xff09; 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq…

stm32 - 初识2

stm32 - 初识2 工程架构点灯程序寄存器方式点灯库函数的方式点灯 工程架构 启动文件 中断向量表&#xff0c;中断服务函数&#xff0c;其他中断等 中断服务函数中的&#xff0c;复位中断是整个程序的入口&#xff0c;调用systeminit&#xff0c;和main函数 点灯程序 寄存器方式…

HTML的相关知识

1.什么是HTML&#xff1f;基本语法 HTML: Hyper Text Markup Language &#xff08;超文本标记语言&#xff09; 超文本&#xff1f;超级文本&#xff0c;例如流媒体&#xff0c;声音、视频、图片等。 标记语言&#xff1f;这种语言是由大量的标签组成。HTML标签参考手…

尚硅谷谷粒商城部分报错问题处理

1、启动报错&#xff1a; 内容&#xff1a; org.springframework.beans.factory.BeanCreationException: Error creating bean with name attrAttrgroupRelationController: Lookup method resolution failed; nested exception is java.lang.IllegalStateException: Failed t…

Redis配置和优化

Redis配置和优化 一 、Redis介绍二、关系数据库和非关系数据库2.1、关系型数据库2.2、 非关系型数据库2.3、 非关系型数据库的产生背景2.4、 关系型数据库和非关系型数据库区别2.5、 总结 三、缓存概念3.1、系统缓存3.2、 缓存保存位置及分层结构3.2.1、DNS缓存3.2.2、 应用层缓…

10.1 File类

前言&#xff1a; java.io包中的File类是唯一一个可以代表磁盘文件的对象&#xff0c;它定义了一些用于操作文件的方法。通过调用File类提供的各种方法&#xff0c;可以创建、删除或者重命名文件&#xff0c;判断硬盘上某个文件是否存在&#xff0c;查询文件最后修改时间&…

【HTML】表格行和列的合并

概述 当我们需要在 HTML 表格中展示复杂的数据时&#xff0c;行和列的合并可以帮助我们实现更灵活的布局和结构。通过合并行和列&#xff0c;我们可以创建具有更多层次和结构的表格&#xff0c;使数据更易于理解和分析。 在 HTML 表格中&#xff0c;我们可以使用 rowspan 和 …

ELK整合springboot(第二课)

一、创建一个springboot的项目 pom文件如下&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLo…

lv5 嵌入式开发-12 信号灯

目录 1 信号量/灯(semaphore)基本概念 2 信号量&#xff0d;&#xff30;&#xff0f;&#xff36;操作概念 3 三种信号灯 3.1 有名信号灯 3.1.1 打开 3.1.2 关闭 3.1.3 删除 3.2 无名信号灯 3.2.1 初始化 3.2.2 销毁 3.3 信号灯P操作 3.4 信号灯V操作 3.5 示例 …

Visual Studio 中将TAB设置为空格

将TAB设置为空格的原因很多&#xff0c;其中一点是为了统一不同编译器对TAB的解释&#xff0c;防止代码风格在不同编译器下不一致等。 在菜单中选择: 工具-->选项-->文本编辑器--->所有语言-->制表符 在窗口中选择&#xff0c;制表符大小和缩进大小都选为4&#xf…

10.1 国庆节小任务

目录 select实现服务器并发 服务器 客户端 运行现象 select实现服务器并发 服务器 #include<myhead.h>#define PORT 8888 //1024~49151 #define IP "192.168.1.104" //ifconfig查看本机IPint main(int argc, const char *argv[]) {//创建流式…

WiFi网络分析工具Airtool for Mac

Airtool是一款Mac平台上的WiFi网络分析工具&#xff0c;它可以帮助用户监测、分析和管理无线网络。 以下是Airtool的一些主要功能和特点&#xff1a; 实时监测&#xff1a;Airtool可以实时监测当前Mac设备所连接的WiFi网络&#xff0c;包括网络速度、信号强度、连接状态等。信…

Spark SQL

Spark SQL 一、Spark SQL概述二、准备Spark SQL的编程环境三、Spark SQL程序编程的入口四、DataFrame的创建五、DataFrame的编程风格六、DataSet的创建和使用七、Spark SQL的函数操作 一、Spark SQL概述 Spark SQL属于Spark计算框架的一部分&#xff0c;是专门负责结构化数据的…

NIO基础

nio : non-blocking io 非阻塞IO 1. 三大组件 1.1 channel和buffer channel 有点像stream &#xff0c;他就是读写数据的双向通道&#xff0c;可以从channel将数据读入buffer&#xff0c;也可以将buffer的数据写入channel&#xff0c;之前的stream 要么输入&#xff0c;要么…

建筑能源管理(3)——建筑能源监管

为了全面落实科学发展观&#xff0c;提高建筑能源管理水平&#xff0c;进一步降低能源和水资源消耗、合理利用资源&#xff0c;以政府办公建筑和大型公共建筑的运行节能管理为突破口&#xff0c;建立了既有政府办公建筑和大型公共建筑运行节能监管体系&#xff0c;旨在提高政府…

28271-2012 米制超细牙螺纹 公差

声明 本文是学习GB-T 28271-2012 米制超细牙螺纹 公差. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本标准规定了米制超细牙螺纹的公差和标记。 本标准适用于精密仪器和电子设备等领域的螺纹连接。 2 规范性引用文件 下列文件对于本文件…

windows server 2019 、win11安装docker desktop

Docker Desktop Docker Desktop是可以部署在windows运行docker的应用服务&#xff0c;其基于windos的Hyper-V服务和WSL2内核在windos上创建一个子系统(linux)&#xff0c;从而实现其在windows上运行docker。 前提条件 WSL 查看wsl是否安装 我们可以直接在 cmd 或 powershe…

MySql出错点

一、DDL 1.修改表&#xff0c;添加新的字段时&#xff0c;不要加引号 2.在修改表中字段的类型时&#xff0c;会发生数据截断。 像DATETIME 转化为 TIME 二、DML 1.插入和删除的注意点 2.可以通过 select 来协助插入 3.