0
点赞
收藏
分享

微信扫一扫

C++面试汇总

逸省 2022-03-12 阅读 64

文章目录

是否了解RAII (Resource Acquisition is Initialization) ?请阐述。

是把资源和对象的生命周期绑定,对象创建获取资源,对象销毁释放资源

设计模式有哪些?特别是单例子模式,工厂模式

· 单例模式:这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

注意:

1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
如日志系统,资源管理器,线程池,内存池等

· 工厂模式:对创建对象的封装,符合开闭原则。工厂模式在许多项目中大量使用,因为它将对象的构造过程封装,使创建对象的接口统一且简洁,另一方面符合开闭原则,易于扩展。开源项目NVDLA的compiler中各类node的建立,LLVM中的pass,都有工厂模式的用例。

· 适配器模式:STL中的容器适配器stack和queue,是对象适配器的绝佳用例。项目开发中也常常使用。

· 观察者模式:频繁使用,观察者模式建立了一种一对多的联动,一个对象改变时将自动通知其他对象,其他对象将作出反应。消息更新、广播机制、消息传递、链式触发(高级啊)……比如Qt的信号槽机制

· 职责链模式:将一个请求的发送者和接收者解耦,让多个对象都有机会处理请求。将接收请求的对象连接成一条链,并且沿着这条链传递请求,直到有一个对象能够处理它为止。采用职责链模式不仅可以方便扩展(当增加一个接受者时,只需要在链上的适当位置插入对应的处理方法即可),而且可以替换掉代码中可能存在的switch-case或者if-else。在工具的设计、具有层级关系或权限关系的任务处理场景中可以应用职责链模式。

· 策略模式:常常与工厂模式搭配,封装不同的算法(策略),再结合C++多态机制,策略模式在实际开发过程中应用十分广泛。
代理模式:C++智能指针、引用计数等

http get 和post请求区别

GET在浏览器回退时是无害的,而POST会再次提交请求。
GET产生的URL地址可以被Bookmark,而POST不可以。
GET请求会被浏览器主动cache,而POST不会,除非手动设置。
GET请求只能进行url编码,而POST支持多种编码方式。
GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
GET请求在URL中传送的参数是有长度限制的,而POST么有。
对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
GET参数通过URL传递,POST放在Request body中。

GET和POST本质上就是TCP链接,并无差别。但是由于HTTP的规定和浏览器/服务器的限制,导致他们在应用过程中体现出一些不同。
对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);

而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。

tcp udp

1.基于连接与无连接;
2.对系统资源的要求(TCP较多,UDP少);
3.UDP程序结构较简单;
4.流模式与数据报模式 ;
5.TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证。
tcp协议和udp协议的差别

TCPUDP
面向连接面向非连接
传输可靠传输不可靠
传输少量数据传输大量数据
速度慢速度快
保证数据正确性可能丢包
保证数据顺序不保证

c++结构体和类的区别和联系

最主要的不同点就是结构体的访问权限为public而且不能改变,而类的访问权限可以改变,public的类和结构体基本一样。

继承上同样表现出这样的特点,struct是public继承的,而class是private继承的,继承的子类的访问权限取决于子类。
其他的struct和class一样可以包含成员函数,可以继承,可以实现多态。

区别起见,我们将结构体中的变量叫做数据,函数叫做函数,类中的变量叫做成员,函数叫做方法。
表现出来的话,结构体更多表现出一种面向过程的数据结构的特点,而类更多表现出面向对象变成的特点,即更侧重对成员的访问权限的控制。

进程 和线程区别

进程:是并发执行的程序在执行过程中分配和管理资源的基本单位,是一个动态概念,竞争计算机系统资源的基本单位。

线程:是进程的一个执行单元,是进程内科调度实体。比进程更小的独立运行的基本单位。线程也被称为轻量级进程。

一个程序至少一个进程,一个进程至少一个线程。

线程执行开销小,但是不利于资源的管理和保护。线程适合在SMP机器(双CPU系统)上运行。
进程执行开销大,但是能够很好的进行资源管理和保护。进程可以跨机器前移。

地址空间:同一进程的线程共享本进程的地址空间,而进程之间则是独立的地址空间。
资源拥有:同一进程内的线程共享本进程的资源如内存、I/O、cpu等,但是进程之间的资源是独立的。
     一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉。所以多进程要比多线程健壮。

进程切换时,消耗的资源大,效率高。所以涉及到频繁的切换时,使用线程要好于进程。同样如果要求同时进行并且又要共享某些变量的并发操作,只能用线程不能用进程

执行过程:每个独立的进程程有一个程序运行的入口、顺序执行序列和程序入口。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
线程是处理器调度的基本单位,但是进程不是。
两者均可并发执行。

dll动态库和lib静态库,

dll动态库和lib静态库详解
静态库的特点:
1、使用静态库的时候,会将静态库的信息直接编译到可执行文件中
2、优点:当静态库被删除,对可执行文件没有影响
3、缺点:浪费内存空间。如果静态库被修改,可执行程序要重新编译

动态库的特点:
加载器在加载动态库时,操作系统会先检查动态库是否因为其它程序已经将这个动态库信息加载到了内存中。如果没有加载到内存中,操作系统会将动态库载入内存,并将它的引用计数设置为1;如果已经加载到内存,仅将动态库的引用计数加1。

. so动态库和. a静态库

静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。编译之后程序文件大,但加载快,隔离性也好。 动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在。多个应用程序可以使用同一个动态库,启动多个应用程序的时候,只需要将动态库加载到内存一次即可。

cpu架构,国产化架构

目前市场上的CPU分类主要分有两大阵营,一个是intel、AMD为首的复杂指令集CPU,另一个是以IBM、ARM为首的精简指令集CPU。不同品牌的CPU,其产品的架构也不相同,Intel、AMD的CPU是X86架构,IBM公司的CPU是PowerPC架构,ARM公司的CPU是ARM架构,国内的飞腾CPU也是ARM架构。此外还有MPIS架构、SPARC架构、Alpha架构。

国产化架构

c++编译命令,gdb调试

  1. 对于 .c和.cpp文件,gcc分别当做c和cpp文件编译(c和cpp的语法强度是不一样的)

  2. 对于 .c和.cpp文件,g++则统一当做cpp文件编译

  3. 使用g++编译文件时,g++会自动链接标准库STL,而gcc不会自动链接STL

  4. gcc在编译C文件时,可使用的预定义宏是比较少的

在这里插入图片描述
GDB

c++标准模板库 stl

STL,英文全称 standard template library,中文可译为标准模板库或者泛型库,其包含有大量的模板类和模板函数,是 C++ 提供的一个基础模板的集合,用于完成诸如输入/输出、数学计算等功能。

从根本上说,STL 是一些容器、算法和其他一些组件的集合,所有容器和算法都是总结了几十年来算法和数据结构的研究成果,汇集了许多计算机专家学者经验的基础上实现的,因此可以说,STL 基本上达到了各种存储方法和相关算法的高度优化。

在STL中体现了泛型程序设计的思想,是以类型参数化的方式实现的(模板)。

STL

STL中的容器:

序列容器:vector string deque list

关联容器:set map multiset multimap

适配容器:stack queue priority_queue(优先队列)
STL分为一元和二元函数两种函数对象。

C++的三大特性:封装、继承、多态。类的基本概念:类,对象,继承。

a.封装:
封装是实现面向对象程序设计的第一步,封装就是将数据或函数等集合在一个个的单元中(我们称之为类)。
封装的意义在于保护或者防止代码(数据)被我们无意中破坏。
b.继承:
继承主要实现重用代码,节省开发时间。
子类可以继承父类的一些东西。
c.多态
多态:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。在运行时,可以通过指向基类的指针,来调用实现派生类中的方法。

C和C++的区别?

答:c++在c的基础上增添类,C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现过程(事务)控制),而对于C++,首要考虑的是如何构造一个对象模型,让这个模型能够契合与之对应的问题域,这样就可以通过获取对象的状态信息得到输出或实现过程(事务)控制。

全局变量和局部变量在内存分配上有何不同?

全局变量保存在内存的全局存储区中,占用静态的存储单元;局部变量保存在栈中,只有在所在函数被调用时才动态地为变量分配存储单元。

static、extern、volatile、const的作用,new与malloc的区别:

static的作用

a.函数体内 static 变量的作用范围为该函数体,不同于 auto 变量, 该变量的内存只被分配一次,因此其值在下次调用时仍维持上次的值

b.在模块内的 static 全局变量可以被模块内所有函数访问,但不能被模块外其他函数访问

c.在模块内的static 函数只可被这一模块内的其他函数调用,这个函数的使用范围被限制在声明它的模块内

d.在类的static 成员变量属于整个类所拥有,对类的所以对象只有一份拷贝

e.在类中的 static 成员函数属于整个类所拥有,这个函数不接收 this 指针,因而只能访问类的 static 成员变量

extern关键字的作用

extern置于变量或函数前,用于标示变量或函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。它只要有两个作用:

当它与“C”一起连用的时候,如:extern “C” void fun(int a,int b);则告诉编译器在编译fun这个函数时候按着C的规矩去翻译,而不是C++的(这与C++的重载有关,C++语言支持函数重载,C语言不支持函数重载,函数被C++编译器编译后在库中的名字与C语言的不同)
当extern不与“C”在一起修饰变量或函数时,如:extern int g_Int;它的作用就是声明函数或全局变量的作用范围的关键字,其声明的函数和变量可以在本模块或其他模块中使用。记住它是一个声明不是定义!也就是说B模块(编译单元)要是引用模块(编译单元)A中定义的全局变量或函数时,它只要包含A模块的头文件即可,在编译阶段,模块B虽然找不到该函数或变量,但它不会报错,它会在连接时从模块A生成的目标代码中找到此函数。

volatile的作用

用来修饰变量的,表明某个变量的值可能会随时被外部改变,因此这些变量的存取不能被缓存到寄存器,每次使用需要重新读取。

假如有一个对象A里面有一个boolean变量a,值为true,现在有两个线程T1,T2访问变量a,T1把a改成了false后T2读取a,T2这时读到的值可能不是false,即T1修改a的这一操作,对T2是不可见的。发生的原因可能是,针对T2线程,为了提升性能,虚拟机把a变量置入了寄存器(即C语言中的寄存器变量),这样就会导致,无论T2读取多少次a,a的值始终为true,因为T2读取了寄存器而非内存中的值。声明了volatile或synchronized 后,就可以保证可见性,确保T2始终从内存中读取变量,T1始终在内存中修改变量。总结:防止脏读,增加内存屏障。

const的作用

定义变量为只读变量,不可修改
修饰函数的参数和返回值(后者应用比较少,一般为值传递)
const成员函数(只需要在成员函数参数列表后加上关键字const,如char get() const;)可以访问const成员变量和非const成员变量,但不能修改任何变量。在声明一个成员函数时,若该成员函数并不对数据成员进行修改操作,应尽可能将该成员函数声明为const成员函数。
const对象只能访问const成员函数,而非const对象可以访问任意的成员函数,包括const成员函数.即对于class A,有const A a;那么a只能访问A的const成员函数。而对于:A b;b可以访问任何成员函数。

使用const关键字修饰的变量,一定要对变量进行初始化

new与malloc的区别

malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。
对于非内部数据类型的对象而言,光用malloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。
new可以认为是malloc加构造函数的执行。new出来的指针是直接带类型信息的。而malloc返回的都是void指针。

指针和引用的区别:

a、指针是一个实体,需要分配内存空间。引用只是变量的别名,不需要分配内存空间。
b、引用在定义的时候必须进行初始化,并且不能够改变。指针在定义的时候不一定要初始化,并且指向的空间可变。(注:不能有引用的值不能为NULL)
c、有多级指针,但是没有多级引用,只能有一级引用。
d、指针和引用的自增运算结果不一样。(指针是指向下一个空间,引用时引用的变量值加1)
e、sizeof 引用得到的是所指向的变量(对象)的大小,而sizeof 指针得到的是指针本身的大小。
f、引用访问一个变量是直接访问,而指针访问一个变量是间接访问。

智能指针:

当类中有指针成员时,一般有两种方式来管理指针成员:一是采用值型的方式管理,每个类对象都保留一份指针指向的对象的拷贝;另一种更优雅的方式是使用智能指针,从而实现指针指向的对象的共享。

智能指针的一种通用实现技术是使用引用计数。智能指针类将一个计数器与类指向的对象相关联,引用计数跟踪该类有多少个对象共享同一指针。

每次创建类的新对象时,初始化指针并将引用计数置为1;当对象作为另一对象的副本而创建时,拷贝构造函数拷贝指针并增加与之相应的引用计数;对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果引用计数为减至0,则删除对象),并增加右操作数所指对象的引用计数;调用析构函数时,构造函数减少引用计数(如果引用计数减至0,则删除基础对象)。

简述深拷贝和浅拷贝的区别:

a.在未定义显示拷贝构造函数的情况下,系统会调用默认的拷贝函数——即浅拷贝,它能够完成成员的一一复制。当数据成员中没有指针时,浅拷贝是可行的;但当数据成员中有指针时,如果采用简单的浅拷贝,则两类中的两个指针将指向同一个地址,当对象快结束时,会调用两次析构函数,而导致指针悬挂现象,所以,此时,必须采用深拷贝。
b.深拷贝与浅拷贝的区别就在于深拷贝会在堆内存中另外申请空间来储存数据,从而也就解决了指针悬挂的问题。简而言之,当数据成员中有指针时,必须要用深拷贝。

编写my_strcpy函数,实现与库函数strcpy类似的功能,不能使用任何库函数;

char *strcpy(char *strDest, const char *strSrc)
{undefined
if ( strDest == NULL || strSrc == NULL)
return NULL ;
if ( strDest == strSrc)
return strDest ;
char *tempptr = strDest ;
while( (*strDest++ = *strSrc++) != ‘’);
returntempptr ;
}

请讲述堆和栈的区别:

a.申请方式不同。栈上有系统自动分配和释放;堆上有程序员自己申请并指明大小;

b.栈是向低地址扩展的数据结构,大小很有限;堆是向高地址扩展,是不连续的内存区域,空间相对大且灵活;

c.栈由系统分配和释放速度快;堆由程序员控制,一般较慢,且容易产生碎片;

全局变量和局部变量有什么区别?实怎么实现的?操作系统和编译器是怎么知道的?

a.生命周期不同:

全局变量随主程序创建和创建,随主程序销毁而销毁

局部变量在局部函数内部,甚至局部循环体等内部存在,退出就不存在; 内存中

分配在全局数据区

b.使用方式不同:通过声明后全局变量程序的各个部分都可以用到;局部变量只能在局部使用,分配在栈区

操作系统和编译器通过内存分配的位置来知道的,全局变量分配在全局数据段并且在程序开始运行的时候被加载。局部变量则分配在堆栈里面

new、delete、malloc、free之间的关系:

new/delete,malloc/free都是动态分配内存的方式

a.malloc对开辟的空间大小严格指定,而new只需要对象名

b.new为对象分配空间时,调用对象的构造函数,delete调用对象的析构函数

既然有了malloc/free,C++中为什么还需要new/delete呢?

因为malloc/free是库函数而不是运算符,不能把执行构造函数和析构函数的功能强加于malloc/free

虚函数是怎么实现的:

虚函数,是指被virtual关键字修饰的成员函数。
虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的。

虚函数的作用,用专业术语来解释就是实现多态性(Polymorphism),多态性是将接口与实现进行分离;用形象的语言来解释就是实现以共同的方法,但因个体差异,而采用不同的策略。

类的示例对象不包含虚函数表,只有虚指针;

派生类会生成一个兼容基类的虚函数表。

虚函数表是针对类的还是针对对象的?同一个类的两个对象的虚函数表是怎么维护的?

编译器为每一个类维护一个虚函数表(本质是一个函数指针数组,数组里面存放了一系列函数地址 ),每个对象的首地址保存着该虚函数表的指针,同一个类的不同对象实际上指向同一张虚函数表。调用形式:*(this指针+调整量)虚函数在vftable内的偏移

在类内部添加一个虚拟函数表指针,该指针指向一个虚拟函数表,该虚拟函数表包含了所有的虚拟函数的入口地址,每个类的虚拟函数表都不一样,在运行阶段可以循此脉络找到自己的函数入口。纯虚函数相当于占位符, 先在虚函数表中占一个位置由派生类实现后再把真正的函数指针填进去。除此之外和普通的虚函数没什么区别。

在单继承形式下,子类的完全获得父类的虚函数表和数据。子类如果重写了父类的虚函数(如fun),就会把虚函数表原本fun对应的记录(内容MyClass::fun)覆盖为新的函数地址(内容MyClassA::fun),否则继续保持原本的函数地址记录。

什么是内存泄漏?面对内存泄漏和指针越界,你有哪些方法?

动态分配内存所开辟的空间,在使用完毕后未手动释放,导致一直占据该内存,即为内存泄漏。

方法:malloc/free要配套,对指针赋值的时候应该注意被赋值的指针是否需要释放;使用的时候记得指针的长度,防止越界

a.类的构造函数和析构函数中new和delete没有配套

b.在释放对象数组时没有使用delete[],使用了delete

c.没有将基类的析构函数定义为虚函数,当基类指针指向子类对象时,如果基类的析构函数不是virtual,那么子类的析构函数将不会被调用,子类的资源没有正确释放,因此造成内存泄露

d.没有正确的清楚嵌套的对象指针

关于构造函数和析构函数:

构造函数的形式很容易辨别,在类中与类同名的成员函数称为构造函数,在初始化一个对象时,如果有初始化数据,先传入到构造函数中,再通过构造函数赋值到类的成员变量中。
所以构造函数相当于一个中介,是向封装好的类初始化数据。另外,需要注意的地方是,类有构造函数的情况下,且构造函数需要传参,则初始化对象时必须要传参。这样可以避免垃圾数据。

构造函数允许重载,所以在实例化对象的时候,可以根据传入参数的不同选择不同的构造函数,但是只会执行其中的一个,具体执行哪一个,按照传入的参数。
析构函数:类名作为函数名,在前面加上~。析构函数不允许重载,并且析构函数无参

通常情况下对象在程序结束的时候会自动调用析构函数,但是需要注意的是动态分配内存的情况。

QT信号槽机制的优缺点

1)QT信号槽机制的引用精简了程序员的代码量
2)QT的信号可以对应多个槽(但他们的调用顺序随机),也可以多个槽映射一个信号
3)QT的信号槽的建立和解除绑定十分自由
4)信号槽同真正的回调函数比起来时间的耗损还是很大的,所有在嵌入式实时系统中应当慎用
5)信号槽的参数限定很多例如不能携带模板类参数,不能出现宏定义等等

多线程情况下, Qt中的信号槽分别在什么线程中执行, 如何控制?

可以通过connect函数的第五个参数来控制, 信号槽执行时所在的线程
1>. 直接连接 – 信号槽函数在信号发出者所在线程中执行
2>. 队列连接 – 信号在信号发出者所在线程中执行,槽函数在信号接收者所在线程中执行.
3>. 自动连接 – 多线程时为队列连接方式, 单线程时为直接连接方式
默认情况为自动连接方式.

描述Qt下Tcp通信的整个流程

服务器端:

  1. 创建用于监听的套接字
  2. 给套接字设置监听
  3. 如果有连接到来, 监听的套接字会发出信号newConnected
  4. 接收连接, 通过nextPendingConnection()函数, 返回一个QTcpSocket类型的套接字对象(用于通信)
  5. 使用用于通信的套接字对象通信
    1>. 发送数据: write
    2>. 接收数据: readAll/read
    客户端:
  6. 创建用于通信的套接字
  7. 连接服务器: connectToHost
  8. 连接成功与服务器通信
    1>. 发送数据: write
    2>. 接收数据: readAll/read

描述QT下udp通信的整个流程

QT下udp通信服务器端和客户端的关系是对等的, 做的处理也是一样的.

  1. 创建套接字对象
  2. 如果需要接收数据, 必须绑定端口
  3. 发送数据: writeDatagram
  4. 接收数据: readDatagram

描述QT下多线程的两种使用方法, 以及注意事项

第一种方法:

  1. 创建一个类从QThread类派生
  2. 在子线程类中重写 run 函数, 将处理操作写入该函数中
  3. 在主线程中创建子线程对象, 启动子线程, 调用start()函数
    第二种方法:
  4. 将业务处理抽象成一个业务类, 在该类中创建一个业务处理函数
  5. 在主线程中创建一QThread类对象
  6. 在主线程中创建一个业务类对象
  7. 将业务类对象移动到子线程中
  8. 在主线程中启动子线程
  9. 通过信号槽的方式, 执行业务类中的业务处理函数
    多线程使用注意事项:
    1. 业务对象, 构造的时候不能指定父对象
    1. 子线程中不能处理ui窗口(ui相关的类)
    1. 子线程中只能处理一些数据相关的操作, 不能涉及窗口

描述QT中的文件流(QTextStream)和数据流(QDataStream)的区别, 他们都能帮助我们完成一些什么事情.

QTextStream – 文本流, 操作轻量级数据(int, double, QString), 数据写入文件中之后以文本的方式呈现。
QDataStream – 数据流, 通过数据流可以操作各种数据类型, 包括类对象, 存储到文件中数据可以还原到内存。
QTextStream, QDataStream可以操作磁盘文件, 也可以操作内存数据, 通过流对象可以将数据打包到内存, 进行数据的传输.

谈谈对C++内存的理解

1、栈区(stack)― 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2、堆区(heap)― 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。
3、全局区(静态区)(static)― 全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放
4、文字常量区 ― 常量字符串就是放在这里的。 程序结束后由系统释放
5、程序代码区 ― 存放函数体的二进制代码。

C++四种强制类型转换

const_cast:从字面意思上就可以理解,去除变量的const属性。
static_cast:静态类型转换,一般用于基本类型间的转换,如char->int
dynamic_cast:动态转换,同于多态之间的类型转换
reinterpret_cast:用于不同类型的指针类型的转换。

动态绑定与静态绑定

静态绑定发生在编译期,动态绑定发生在运行期;
对象的动态类型可以更改,但是静态类型无法更改;
要想实现动态,必须使用动态绑定;
在继承体系中只有虚函数使用的是动态绑定,其他的全部是静态绑定;
静态多态是指通过模板技术或者函数重载技术实现的多态,其在编译器确定行为。动态多态是指通过虚函数技术实现在运行期动态绑定的技术
动态绑定:有一个基类,两个派生类,基类有一个virtual函数,两个派生类都覆盖了这个虚函数。现在有一个基类的指针或者引用,当该基类指针或者引用指向不同的派生类对象时,调用该虚函数,那么最终调用的是该被指向对象对应的派生类自己实现的虚函数。

举报

相关推荐

0 条评论