C++面试宝典 基本语言(三)

如果同时定义了两个函数,一个带const,一个不带,会有问题吗?

  • 不会,这相当于函数的重载
#include<iostream>
class A{
public:void print()const{std::cout << "Hello" << std::endl;}void print(){std::cout << "World" << std::endl;}
};
int main(){A a{};const A const_a;a.print();const_a.print();return 0;
}

请你来说一说隐式类型转换

  • 首先,对于内置类型,低精度的变量给高精度变量赋值会发生隐式类型转换,   int  ->  double
  • 其次,对于只存在单个参数的构造函数的对象构造来说,函数调用可以直接使用该参数传入,编译器会自动调用其构造函数生成临时对象

注意事项

  • “可以用单个形参进行调用” 并不是指构造函数只能有一个形参,而是它可以有多个形参,但那些形参都是有默认实参的。 那么,什么是“隐式转换”呢? 上面这句话也说了,是从 构造函数形参类型 到 该类类型 的一个编译器的自动转换
  • 代码中可以看到,isSameISBN函数是期待一个BOOK类类型形参的,但我们却传递了一个string类型的给它,这不是它想要的啊!还好,BOOK类中有个构造函数,它使用一个string类型实参进行调用,编译器调用了这个构造函数隐式地将stirng类型转换为BOOK类型(构造了一个BOOK临时对象),再传递给isSameISBN函数。 隐式类类型转换还是会带来风险的,正如上面标记,隐式转换得到类的临时变量,完成操作后就消失了,我们构造了一个完成测试后被丢弃的对象。 我们可以通过explicit声明来抑制这种转换:
  • explicit BOOK(string ISBN,float price=0.0f):_bookISBN(ISBN),_price(price){}
  • explicit关键字只能用于类内部的构造函数声明上.这样一来,BOOK类构造函数就不能用于隐式地创造对象了
  • 可以使用一个实参进行调用,不是指构造函数只能有一个形参。 隐式类类型转换容易引起错误,除非你有明确理由使用隐式类类型转换,否则,将可以用一个实参进行调用的构造函数都声明为explicit。    
  •  explicit只能用于类内部构造函数的声明。它虽然能避免隐式类型转换带来的问题,但需要用户能够显式创建临时对象(对用户提出了要求)。
#include <string>
#include <iostream>
using namespace std ;
class BOOK  //定义了一个书类
{
private:string _bookISBN ;  //书的ISBN号float _price ;    //书的价格public://定义了一个成员函数,这个函数即是那个“期待一个实参为类类型的函数”//这个函数用于比较两本书的ISBN号是否相同bool isSameISBN(const BOOK & other ){return other._bookISBN==_bookISBN;}//类的构造函数,即那个“能够用一个参数进行调用的构造函数”(虽然它有两个形参,但其中一个有默认实参,只用一个参数也能进行调用)BOOK(string ISBN,float price=0.0f):_bookISBN(ISBN),_price(price){}
};int main()
{BOOK A("A-A-A");BOOK B("B-B-B");cout<<A.isSameISBN(B)<<endl;   //正经地进行比较,无需发生转换cout<<A.isSameISBN(string("A-A-A"))<<endl; //此处即发生一个隐式转换:string类型-->BOOK类型,借助BOOK的构造函数进行转换,以满足isSameISBN函数的参数期待。cout<<A.isSameISBN(BOOK("A-A-A"))<<endl;    //显式创建临时对象,也即是编译器干的事情。}

说说你了解的类型转换

  • reinterpret_cast:可以用于任意类型的指针之间的转换,对转换的结果不做任何保证
  • dynamic_cast:这种其实也是不被推荐使用的,更多使用static_cast,dynamic本身只能用于存在虚函数的父子关系的强制类型转换,对于指针,转换失败则返回nullptr,对于引用,转换失败会抛出异常。(1)dynamic_cast是运行时处理的,运行时要进行类型检查,而其他三种都是编译时完成的;(2)不能用于内置基本数据类型间的强制转换;(3)使用dynamic_cast进行转换时,基类中一定要有虚函数,否则编译不通过;(4)dynamic_cast转换若成功,返回的是指向类的指针或引用;若失败则会返回NULL;(5)在类的转换时,在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的。在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。向下转换的成败取决于将要转换的类型,即要强制转换的指针所指向的对象实际类型与将要转换后的类型一定要相同,否则转换失败。  下行转换,使用基类class  创建 其派生类对象的时候,新建的对象只可以使用 基类的相关public、protected内容 和 本派生类所创建的独有的方法
  • 参考此例子  
#include <iostream>class Shape{
public:Shape();virtual ~Shape();virtual double calcArea();protected:double i_mNumber;
};class Circle : public Shape{
public:Circle(double r);~Circle();
protected:double m_iR;
};
int main(){double x = 2.5;//static_castint y = (int)x;//C语言int z = static_cast<int>(x);//C++//dynamic_castShape *p = new Circle(2.0);Circle *q = dynamic_cast<Circle *>(p);//reinterpret_castint r = 1000;int *w = reinterpret_cast<int *>(r);//将数值转化为地址 很危险//const int c = 0;
//    int *o = &x;//Errorint *g = const_cast<int *>(&c);
}

参考链接

  • C++中四种cast(强制)转换 
  • const_cast:对于未定义const版本的成员函数,我们通常需要使用const_cast来去除const引用对象的const,完成函数调用。另外一种使用方式,结合static_cast,可以在非const版本的成员函数内添加const,调用完const版本的成员函数后,再使用const_cast去除const限定
  • static_cast:完成基础数据类型;同一个继承体系中类型的转换;任意类型与空指针类型void* 之间的转换

参考链接

  • 你必须知道的指针基础-8.栈空间与堆空间 
  • 栈空间和堆空间大小

 请你来说一说C++函数栈空间的最大值

  • 默认是1M,不过可以调整 
  • 补充:window和Linux不一样,linux如图stack size所示 为8kb,win为2kb;而堆本质是使用链表的形式申请内存空间,和操作系统的虚拟内存挂钩,一般大小为2G

请你来说一说extern“C”

  • C++调用C函数需要extern C,因为C语言没有函数重载

参考链接

  • extern “C”的作用详解
  • extern "C":实现C++和C的混合编程

请你回答一下new/delete与malloc/free的区别是什么

  • 首先,new/delete是C++的关键字,而malloc/free是C语言的库函数,后者使用必须指明申请内存空间的大小,对于类类型的对象,后者不会调用构造函数和析构函数

补充

  • 1、new分配内存按照数据类型进行分配,malloc分配内存按照指定的大小分配;
  • 2、new返回的是指定对象的指针,而malloc返回的是void*,因此malloc的返回值一般都需要进行类型转化
  • 3、new不仅分配一段内存,而且会调用构造函数,malloc不会。
  • 4、new分配的内存要用delete销毁,malloc要用free来销毁;delete销毁的时候会调用对象的析构函数,而free则不会。
  • 5、new是一个操作符可以重载malloc是一个库函数
  • 6、malloc分配的内存不够的时候,可以用realloc扩容。new没用这样操作。
  • 7、new如果分配失败了会抛出bad_malloc的异常,而malloc失败了会返回NULL。
  • 8、申请数组时:new[]一次分配所有内存,多次调用构造函数,搭配使用delete[]。delete[]多次调用析构函数,销毁数组中的每个对象。而malloc则只能sizeof(int) * n。

参考链接

  • 请你来回答一下new和malloc的区别

请你说说你了解的RTTI

  • 运行时类型检查,在C++层面主要体现在dynamic_casttypeid,VS中虚函数表的-1位置存放了指向type_info的指针。对于存在虚函数的类型,typeid和dynamic_cast都会去查询type_info

参考链接

  • RTTI
  • C++中的RTTI机制
  • Chapter12:多态——从虚函数表到RTTI(二)

请你说说虚函数表具体是怎样实现运行时多态的?

  • 子类若重写父类虚函数,虚函数表中,该函数的地址会被替换,对于存在虚函数的类的对象,在VS中,对象的对象模型的头部存放指向虚函数表的指针,通过该机制实现多态。

请你说说C语言是怎么进行函数调用的?

  • 每一个函数调用都会分配函数栈,在栈内进行函数执行过程。调用前,先把返回地址压栈,然后把当前函数的esp指针压栈。

请你说说C语言参数压栈顺序?

  • 从右到左

请你说说C++如何处理返回值?

生成一个临时变量,把它的引用作为函数参数传入函数内

请你回答一下C++中拷贝赋值函数的形参能否进行值传递?

  • 不能。如果是这种情况下,调用拷贝构造函数的时候,首先要将实参传递给形参,这个传递的时候又要调用拷贝构造函数。如此循环,无法完成拷贝,栈也会满。

请你回答一下malloc与new区别

  • malloc需要给定申请内存的大小,返回的void* 指针需要强转
  • new会调用构造函数,不用指定内存大小,返回的指针不用强转

请你说一说select

  • select在使用前,先将需要监控的描述符对应的bit位置1,然后将其传给select,当有任何一个事件发生时,select将会返回所有的描述符,需要在应用程序自己遍历去检查哪个描述符上有事件发生,效率很低,并且其不断在内核态和用户态进行描述符的拷贝,开销很大

 请你说说fork,wait,exec函数

  • 父进程产生子进程使用fork拷贝出来一个父进程的副本,此时只拷贝了父进程的页表,两个进程都读同一块内存,当有进程写的时候使用写实拷贝机制分配内存
  • exec函数可以加载一个elf文件去替换父进程,从此父进程和子进程就可以运行不同的程序了。fork从父进程返回子进程的pid,从子进程返回0.调用了wait的父进程将会发生阻塞,直到有子进程状态改变,执行成功返回0,错误返回-1。
  • exec执行成功则子进程从新的程序开始运行,无返回值,执行失败返回-1

请你回答一下静态函数和虚函数的区别

  • 静态函数在编译的时候就已经确定运行时机,虚函数在运行的时候动态绑定。虚函数因为用了虚函数表机制,调用的时候会增加一次内存开销,动态切换

请你说一说重载和覆盖

  • 重载:两个函数名相同,但是参数列表不同(个数,类型),返回值类型没有要求,在同一作用域中
  • 重写:子类继承了父类,父类中的函数是虚函数,在子类中重新定义了这个虚函数,这种情况是重写

请你说一说static关键字

  • 1.加了static关键字的全局变量只能在本文件中使用。例如在a.c中定义了static int a=10;那么在b.c中用extern int a是拿不到a的值,a的作用域只在a.c中。
  • 2.static定义的静态局部变量分配在数据段上,普通的局部变量分配在栈上,会因为函数栈帧的释放而被释放掉。
  • 3. 对一个类中成员变量和成员函数来说,加了static关键字,则此变量/函数就没有了this指针了,必须通过类名才能访问

请你说一说strcpy和strlen

  • strcpy是字符串拷贝函数,原型:  char *strcpy(char* dest, const char *src);
  • 从src逐字节拷贝到dest,直到遇到'\0'结束,因为没有指定长度,可能会导致拷贝越界,造成缓冲区溢出漏洞,安全版本是strncpy函数。
  • strlen函数是计算字符串长度的函数,返回从开始到'\0'之间的字符个数。

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

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

相关文章

C++ primer 第9章 顺序容器

文章目录顺序容器类型确定使用哪种顺序容器容器库概览容器操作迭代器迭代器支持的所有操作迭代器支持的所有运算迭代器范围对构成范围的迭代器的要求标准库迭代器范围左闭右开的三种性质容器定义和初始化将一个新容器创建为另一个容器的拷贝将array拷贝到vector中的代码与顺序容…

牛客网C++面经 容器和算法

原文网址 参考网址 C语言中文网 请你来说一下map和set有什么区别&#xff0c;分别又是怎么实现的&#xff1f; map和set都是C的关联容器&#xff0c;其底层实现都是红黑树&#xff08;RB-Tree&#xff09;。由于 map 和set所开放的各种操作接口&#xff0c;RB-tree 也都提供…

C++ primer 第10章 泛型算法

文章目录概述findcount初识泛型算法只读算法只读算法accumulate只读算法equal写容器元素的算法算法fill算法fill_nback_inserter算法copy算法replace replace_copy重排容器元素的算法sortuniqueunique_copy定制操作向算法传递函数谓词算法stable_sort算法partitionlambda表达式…

C语言常用字符串函数

概括 代码 #include<stdlib.h> #include<stdio.h> #include<string.h> int main() {//常用字符串函数char a[]"abcSDFbnm";char b[]"SD";printf("a的字符串长度:%d\n",strlen(a));printf("b的字符串长度:%d\n",str…

C++ primer 第11章 关联容器

文章目录使用关联容器map示例关联容器概述定义关联容器关联容器值初始化multimap和multiset关键字类型的要求pair类型pair上的操作关联容器操作关联容器额外的类型别名关联容器迭代器map迭代器set迭代器关联容器和算法添加元素向map添加元素检测insert的返回值使用insert代替下…

C++ primer 第12章 动态内存

文章目录前言动态内存与智能指针shared_ptr类shared_ptr和unique_ptr都支持的操作shared_ptr独有的操作make_shared 函数shared_ptr的拷贝和赋值shared_ptr自动销毁所管理的对象shared_ptr还会自动释放相关联的内存程序使用动态内存出于以下原因直接管理内存使用new动态分配和初…

C语言顺序查找二分查找

介绍 顺序查找 按照顺序一个个查找 #include<stdio.h> //顺序查找 int search(int arr[],int len,int aim) {int i;for(i0;i<len;i){if(arr[i]aim){return i;//返回下标 }}return -1;//表示未查询到} int main() {int arr[]{13,355,256,65,234,-1,35,-6,-3,-4,0};…

C++ primer 第12章 12.3 使用标准库:文本查询程序

文章目录使用标准库&#xff1a;文本查询程序文本查询程序设计数据结构在类之间共享数据自己的文本查询程序书中的文本查询程序使用标准库&#xff1a;文本查询程序 我们将实现一个简单的文本查询程序&#xff0c;作为标准库相关内容学习的总结。 我们的程序允许用户在一个给…

C语言二维数组 int arr[2][3]

基础使用 先遍历行再遍历列 #include<stdio.h> //二维数组的基本使用 int main() {//二维数组的初始化int arr1[2][2]{{2,2},{0,0}};int arr2[2][3]{2,2,2,8,8,8};int arr3[6][9];int i,j;for(i0;i<6;i){for(j0;j<9;j){arr3[i][j]1;}}arr3[2][5]0;//打印printf(&…

C++ primer 第13章 拷贝控制

文章目录前言拷贝、赋值与销毁拷贝构造函数合成拷贝构造函数拷贝初始化和直接初始化拷贝初始化的发生&#xff1a;参数和返回值拷贝初始化的限制拷贝赋值运算符重载赋值运算符合成拷贝赋值运算符析构函数析构函数完成的工作什么时候会调用析构函数合成析构函数代码片段调用几次…

C语言 指针自增自减加减运算 p++ p+i

介绍 自增自减代码 #include<stdio.h> #include<string.h> //指针自增--short void increase(short *arr,int len) {int i;arr&arr[0];for(i0;i<len;i){printf("arr[%d]%d,address%p\n",i,*arr,arr);arr;} }//指针自减--char void decrease(char…

C++ 编译与底层

原文链接 编译与底层请你来说一下一个C源文件从文本到可执行文件经历的过程&#xff1f; 对于C源文件&#xff0c;从文本到可执行文件一般需要四个过程&#xff1a;预处理阶段&#xff1a;对源代码文件中文件包含关系&#xff08;头文件&#xff09;、预编译语句&#xff08;…

C语言 指针数组-字符指针数组整型指针数组 char*s[3] int*a[5] 数组指针int(*p)[4]

基本介绍 1.指针数组:由n个指向整型元素的指针而组成,里面存放指针 Int *ptr[3]; 2.地址: ptr[i]:元素地址 &ptr[i]:指针地址 图示 代码: 内存布局: 代码 #include<stdio.h> #include<string.h> //指针数组--int void pointer(int *arr,int len) {int …

C语言 多重指针--整型字符字符串 int**pp

介绍 多重指针:一个指针指向另一个指针 离值越近的指针级别越大:一级 内存布局 代码 图示: 多重指针–整型 #include<stdio.h> #include<string.h> //多重指针--整型//二级指针 void two() {printf("二级指针:\n");int a896;int *p&a,**pp&…

C++ primer 第13章 拷贝控制

文章目录前言拷贝、赋值与销毁拷贝构造函数合成拷贝构造函数拷贝初始化和直接初始化拷贝初始化的发生&#xff1a;参数和返回值拷贝初始化的限制拷贝赋值运算符重载赋值运算符合成拷贝赋值运算符析构函数析构函数完成的工作什么时候会调用析构函数合成析构函数代码片段调用几次…

牛客网C++面经 C++11

请问C11有哪些新特性&#xff1f; auto关键字&#xff1a;编译器可以根据初始值自动推导出类型。但是不能用于函数传参以及数组类型的推导nullptr关键字&#xff1a;nullptr是一种特殊类型的字面值&#xff0c;它可以被转换成任意其它的指针类型&#xff1b;而NULL一般被宏定义…

C语言 返回指针的函数--指针函数 int* max(int a)

定义 strlong示例代码 代码1: #include<stdio.h> #include<string.h> //返回指针的函数//比较两个字符串,返回更长的字符串 char *strlong(char* a,char* b) {char *p1&a[0];char *p2&b[0];while(true){if(*p1\0){return b;}else if(*p2\0){return a;}p1…

第2、3讲 图像的存储格式

本图像处理系列笔记是基于B站杨淑莹老师的课程进行学习整理的。 文章目录黑白图像8位灰度索引图像8位伪彩色索引图像24位真彩色图像图像文件格式BMP文件存储格式BMP文件头位图信息头颜色表位图信息——BITMAPINFO结构BMP位图文件汇总按照颜色深度分类&#xff0c;常用图像文件&…

Ubuntu18.04.4 环境下对属性加密算法CP-ABE环境搭建

注意事项 cpabe依赖pbc&#xff0c;pbc依赖gmp&#xff0c;gmp依赖M4、bison、flex如果权限不够 &#xff0c;命令的前面加上sudo &#xff0c;不要直接使用root用户进行操作&#xff0c;其带来的隐患有很多 第一步 配置简单的环境 简单环境 包括gcc、g、make、cmake、openss…

C语言 函数指针 int(*ptr)(int,int)

基本介绍 函数指针:指向函数的指针 与数组类似 定义 Int(*pmax)(int ,int)max; Int(*pmax)(int x,int y)max;//形参名称不重要 函数返回类型(*指针)(形参类型)函数名称; 具体案例 代码: *pmax取到函数本身 调用函数指针方式: (*pmax)(x,y); pmax(x,y);//与java中调用函数一…