腾讯技术岗位笔试&面试题(六)

说在前面

本篇文章是腾讯技术面试题目汇总第六篇
后续将持续推出互联网大厂,如阿里,腾讯,百度,美团,头条等技术面试题目,以及答案和分析。
欢迎大家点赞关注转发。

1.定义和声明的区别

  1. 如果是指变量的声明和定义
    从编译原理上来说,声明是仅仅告诉编译器,有个某类型的变量会被使用,但是编译器并不会为它分配任何内存。而定义就是分配了内存。
  2. 如果是指函数的声明和定义
    声明:一般在头文件里,对编译器说:这里我有一个函数叫function() 让编译器知道这个函数的存在。
    定义:一般在源文件里,具体就是函数的实现过程 写明函数体。

2.C++类型转换有四种

  1. static_cast能进行基础类型之间的转换,也是最常看到的类型转换。它主要有如下几种用法:

    • 用于类层次结构中父类和子类之间指针或引用的转换。进行上行转换(把子类的指针或引用转换成父类表示)是安全的;
    • 进行下行转换(把父类指针或引用转换成子类指针或引用)时,由于没有动态类型检查,所以是不安全的;
    • 用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。
    • 把void指针转换成目标类型的指针(不安全!!)
    • 把任何类型的表达式转换成void类型。
  2. const_cast运算符用来修改类型的const或volatile属性。除了去掉const 或volatile修饰之外, type_id和expression得到的类型是一样的。但需要特别注意的是const_cast不是用于去除变量的常量性,而是去除指向常数对象的指针或引用的常量性,其去除常量性的对象必须为指针或引用。

  3. reinterpret_cast它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,在把该整数转换成原类型的指针,还可以得到原先的指针值)。

  4. dynamic_cast主要用在继承体系中的安全向下转型。它能安全地将指向基类的指针转型为指向子类的指针或引用,并获知转型动作成功是否。转型失败会返回null(转型对象为指针时)或抛出异常bad_cast(转型对象为引用时)。 dynamic_cast 会动用运行时信息(RTTI)来进行类型安全检查,因此 dynamic_cast 存在一定的效率损失。当使用dynamic_cast时,该类型必须含有虚函数,这是因为dynamic_cast使用了存储在VTABLE中的信息来判断实际的类型,RTTI运行时类型识别用于判断类型。typeid表达式的形式是typeid(e),typeid操作的结果是一个常量对象的引用,该对象的类型是type_info或type_info的派生。

3.全局变量和static变量的区别

  1. 全局变量(外部变量)的说明之前再冠以static就构成了静态的全局变量。全局变量本身就是静态存储方式,静态全局变量当然也是静态存储方式。
    这两者在存储方式上并无不同。这两者的区别在于非静态全局变量的作用域是整个源程序,当一个源程序由多个原文件组成时,非静态的全局变量在各个源文件中都是有效的。而静态全局变量则限制了其作用域,即只在定义该变量的源文件内有效,在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域限于一个源文件内,只能为该源文件内的函数公用,因此可以避免在其他源文件中引起错误。static全局变量与普通的全局变量的区别是static全局变量只初始化一次,防止在其他文件单元被引用。
  2. static函数与普通函数有什么区别?
    static函数与普通的函数作用域不同。尽在本文件中。只在当前源文件中使用的函数应该说明为内部函数(static),内部函数应该在当前源文件中说明和定义。对于可在当前源文件以外使用的函数应该在一个头文件中说明,要使用这些函数的源文件要包含这个头文件。
    static函数与普通函数最主要区别是static函数在内存中只有一份,普通静态函数在每个被调用中维持一份拷贝程序的局部变量存在于(堆栈)中,全局变量存在于(静态区)中,动态申请数据存在于(堆)

4.静态成员与普通成员的区别

  1. 生命周期
    静态成员变量从类被加载开始到类被卸载,一直存在;
    普通成员变量只有在类创建对象后才开始存在,对象结束,它的生命期结束;
  2. 共享方式
    静态成员变量是全类共享;普通成员变量是每个对象单独享用的;
  3. 定义位置
    普通成员变量存储在栈或堆中,而静态成员变量存储在静态全局区;
  4. 初始化位置
    普通成员变量在类中初始化;静态成员变量在类外初始化;
  5. 默认实参
    可以使用静态成员变量作为默认实参.

5.说一下理解 ifdef endif

  1. 一般情况下,源程序中所有的行都参加编译。但是有时希望对其中一部分内容只在满足一定条件才进行编译,也就是对一部分内容指定编译的条件,这就是“条件编译”。有时,希望当满足某条件时对一组语句进行编译,而当条件不满足时则编译另一组语句。
  2. 条件编译命令最常见的形式为:

    ifdef 标识符

    程序段1

    else

    程序段2

    endif

    它的作用是:当标识符已经被定义过(一般是用#define命令定义),则对程序段1进行编译,否则编译程序段2。
    其中#else部分也可以没有,即:

    ifdef

    程序段1

    denif

  3. 在一个大的软件工程里面,可能会有多个文件同时包含一个头文件,当这些文件编译链接成一个可执行文件上时,就会出现大量“重定义”错误。在头文件中使用#define、#ifndef、#ifdef、#endif能避免头文件重定义。

6.隐式转换,如何消除隐式转换?

  1. C++的基本类型中并非完全的对立,部分数据类型之间是可以进行隐式转换的。所谓隐式转换,是指不需要用户干预,编译器私下进行的类型转换行为。很多时候用户可能都不知道进行了哪些转换

  2. C++面向对象的多态特性,就是通过父类的类型实现对子类的封装。通过隐式转换,你可以直接将一个子类的对象使用父类的类型进行返回。在比如,数值和布尔类型的转换,整数和浮点数的转换等。某些方面来说,隐式转换给C++程序开发者带来了不小的便捷。C++是一门强类型语言,类型的检查是非常严格的。

  3. 基本数据类型 基本数据类型的转换以取值范围的作为转换基础(保证精度不丢失)。隐式转换发生在从小->大的转换中。比如从char转换为int。从int->long。自定义对象 子类对象可以隐式的转换为父类对象。

  4. C++中提供了explicit关键字,在构造函数声明的时候加上explicit关键字,能够禁止隐式转换。

  5. 如果构造函数只接受一个参数,则它实际上定义了转换为此类类型的隐式转换机制。可以通过将构造函数声明为explicit加以制止隐式类型转换,关键字explicit只对一个实参的构造函数有效,需要多个实参的构造函数不能用于执行隐式转换,所以无需将这些构造函数指定为explicit。

7.多继承的优缺点,作为一个开发者怎么看待多继承

  1. C++允许为一个派生类指定多个基类,这样的继承结构被称做多重继承。
  2. 多重继承的优点很明显,就是对象可以调用多个基类中的接口;
  3. 如果派生类所继承的多个基类有相同的基类,而派生类对象需要调用这个祖先类的接口方法,就会容易出现二义性
  4. 加上全局符确定调用哪一份拷贝。比如pa.Author::eat(. 调用属于Author的拷贝。
  5. 使用虚拟继承,使得多重继承类Programmer_Author只拥有Person类的一份拷贝。

8.迭代器++it,it++哪个好,为什么

1)前置返回一个引用,后置返回一个对象

// ++i实现代码为:
int& operator++()

{
*this += 1;

  return *this;

}

  1. 前置不会产生临时对象,后置必须产生临时对象,临时对象会导致效率降低

//i++实现代码为:
int operator++(int)
{

int temp = *this;

++*this;

return temp;

}

欢迎start和follow我们的仓库,里面有更多信息,包含大厂技术岗位面试笔试题库/大厂面试经验分享/学习资料/最新求职信息和内推职位/学长学姐交流学习/计算机毕设课题和源码/算法求职/各城市大厂推荐等,旨在帮助学计算机、编程的同学少走弯路,减少信息差,成功拿到理想的offer

posted @ 2024-12-18 18:00  AutoDriver  阅读(13)  评论(0编辑  收藏  举报