十八万字吐血整理的C/C++、嵌入式常见面试题!!!!

欢迎订阅,希望能点个赞!!!!

正在持续更新!!!!!欢迎探讨!!!

完整专栏地址:https://blog.nowcoder.net/zhuanlan/gmPWX0


相关知识点都能零星在网上找到,这个文章系列将目前遇到的所有常见面试问题进行一个汇总。

文中很多资料避免不了从网上或是其他复习资料里收集整理,十分感谢前辈的辛勤付出,如果存在侵权请一定联系我进行删除

也有相当一部分是本人在经历提前批以及秋招的过程中遇到和验证过的。


系列文章PDF下载地址:《最全C_C++及嵌入式软开面试题宝典.pdf》



61、虚函数的代价?

1.带有虚函数的类,每一个类会产生一个虚函数表,用来存储指向虚成员函数的指针,增大类;

2.带有虚函数的类的每一个对象,都会有一个指向虚表的指针,会增加对象的空间大小;

3.不能再是内联的函数,因为内联函数在编译阶段进行替代,而虚函数表示等待,在运行阶段才能确定到底是采用哪种函数,虚函数不能是内联函数。

62、用C语言实现C++的继承


#include <iostream>
using namespace std;
//C++中的继承与多态
struct A
{
    virtual void fun()    //C++中的多态:通过虚函数实现
    {
        cout<<"A:fun()"<<endl;
    }
    int a;
};

struct B:public A         //C++中的继承:B类公有继承A类
{
    virtual void fun()    //C++中的多态:通过虚函数实现(子类的关键字virtual可加可不加)
    {
        cout<<"B:fun()"<<endl;
    }
    int b;
};

//C语言模拟C++的继承与多态
typedef void (*FUN)();      //定义一个函数指针来实现对成员函数的继承
struct _A       //父类
{
    FUN _fun;   //由于C语言中结构体不能包含函数,故只能用函数指针在外面实现
    int _a;
};
struct _B         //子类
{
    _A _a_;     //在子类中定义一个基类的对象即可实现对父类的继承
    int _b;
};
void _fA()       //父类的同名函数
{
    printf("_A:_fun()\n");
}
void _fB()       //子类的同名函数
{
    printf("_B:_fun()\n");
}
void Test()
{
    //测试C++中的继承与多态
    A a;    //定义一个父类对象a
    B b;    //定义一个子类对象b

    A* p1 = &a;   //定义一个父类指针指向父类的对象
    p1->fun();    //调用父类的同名函数

    p1 = &b;      //让父类指针指向子类的对象
    p1->fun();    //调用子类的同名函数

    //C语言模拟继承与多态的测试
    _A _a;    //定义一个父类对象_a
    _B _b;    //定义一个子类对象_b
    _a._fun = _fA;        //父类的对象调用父类的同名函数
    _b._a_._fun = _fB;    //子类的对象调用子类的同名函数

    _A* p2 = &_a;   //定义一个父类指针指向父类的对象
    p2->_fun();     //调用父类的同名函数

    p2 = (_A*)&_b;  //让父类指针指向子类的对象,由于类型不匹配所以要进行强转
    p2->_fun();     //调用子类的同名函数

}

63、继承机制中对象之间如何转换?指针和引用之间如何转换?


1.向上类型转换

将派生类指针或引用转换为基类的指针或引用被称为向上类型转换,向上类型转换会自动进行,而且向上类型转换是安全的。

2.向下类型转换

将基类指针或引用转换为派生类指针或引用被称为向下类型转换,向下类型转换不会自动进行,因为一个基类对应几个派生类,所以向下类型转换时不知道对应哪个派生类,所以在向下类型转换时必须加动态类型识别技术。RTTI技术,用dynamic_cast进行向下类型转换。

64、C++四种类型转换

C++的四种强制转换包括:static_cast, dynamic_cast, const_cast, reinterpret_cast。

1.static_cast能进行基础类型之间的转换,也是最常看到的类型转换。明确指出类型转换,⼀般建议将隐式转换都替换成显示转换,因为没有动态类型检查,上⾏转换(派⽣类->基类)安全,下⾏转换(基类->派⽣类) 不安全,所以主要执⾏⾮多态的转换操作;

它主要有如下几种用法:


  • 用于类层次结构中父类和子类之间指针或引用的转换。进行上行转换(把子类的指针或引用转换成父类表示)是安全的;
  • 进行下行转换(把父类指针或引用转换成子类指针或引用)时,由于没有动态类型检查,所以是不安全的;
  • 用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。
  • 把void指针转换成目标类型的指针(不安全!!)
  • 把任何类型的表达式转换成void类型。


2.const_cast专⻔⽤于const,volatile属性的转换,去除const性质,或增加const性质,是四个转换符中唯⼀⼀个可以操作常量的转换符。除了去掉const 或volatile修饰之外,type_id和expression得到的类型是一样的。但需要特别注意的是const_cast不是用于去除变量的常量性,而是去除指向常数对象的指针或引用的常量性,其去除常量性的对象必须为指针或引用。

3.reinterpret_cast不到万不得已,不要使⽤这个转换符,⾼危操作。使⽤特点:从底层对数据进⾏重新解释,依赖具体的平台,可移植性差。它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,在把该整数转换成原类型的指针,还可以得到原先的指针值)。可以在指针和引⽤之间进⾏肆⽆忌惮的转换。

4.dynamic_cast 专⻔⽤于派⽣类之间的转换,type-id必须是类指针,类引⽤或void*,主要用在继承体系中的安全向下转型。它能安全地将指向基类的指针转型为指向子类的指针或引用,并获知转型动作成功是否。当类型不⼀致时,转型失败会返回null(转型对象为指针时)或抛出异常bad_cast(转型对象为引用时),⽽static_cast,当类型不⼀致时,转换过来的事错误意义的指针,可能造成⾮法访问等问题。dynamic_cast 会动用运行时信息(RTTI)来进行类型安全检查,因此 dynamic_cast 存在一定的效率损失。当使用dynamic_cast时,该类型必须含有虚函数,这是因为dynamic_cast使用了存储在VTABLE中的信息来判断实际的类型,RTTI运行时类型识别用于判断类型。typeid表达式的形式是typeid(e),typeid操作的结果是一个常量对象的引用,该对象的类型是type_info或type_info的派生。

65、为什么要用static_cast转换而不用c语言中的转换?

1.更加安全;

2.更直接明显,能够一眼看出是什么类型转换为什么类型,容易找出程序中的错误;可清楚地辨别代码中每个显式的强制转;可读性更好,能体现程序员的意图