【C++后台开发面试】C++语言相关(一)

参考出处:https://blog.csdn.net/jiange_zh/article/details/71714005

1.多态

  • 面向对象的语言有三大特性:继承、封装、多态。其中多态分为两种:即静态多态和动态多态;
  • 静态多态可以称为编译期多态,它是在编译期间通过函数重载和运算符重载的方式决定被调用函数;
  • 动态多态可以称为运行期多态,它可以通过继承和虚函数来实现。实现时,编译器将在进程运行的过程中动态的捆绑想要调用的函数;
  • 多态实现有三个必要条件:继承,父类指针指向子类对象,子类重写父类虚函数。

2.虚函数

首先了解下多态的实现原理 C/C++—— 对多态现象的理解

  • 当类声明虚函数时,编译器会在类中生产一个虚函数表,用来存储类成员函数指针,虚函数表是由编译器自动生产与维护的。
  • 继承时会继承父类的虚函数表,如果子类没有重写父类虚函数,虚表与父类的虚表无异,如果重写了,子类虚函数在虚表的对应指针的位置会被修改为子类虚函数指针。多继承时子类会有多个表。
    这里写图片描述
    这里写图片描述
  • 对于一个实例对象,会有一个虚指针(只有一个) 指向虚表,执行前的查表所用。 有子类时,析构函数必须是虚函数。构造函数不能是虚函数(没有意义,底层相关):网络上还有一个很普遍的解释是这样的:虚函数对应一个指向vtable虚函数表的指针,但是这个指向vtable的指针事实上是存储在对象的内存空间的。假设构造函数是虚的,就须要通过 vtable来调用,但是对象还没有实例化,也就是内存空间还没有,怎么找vtable呢?所以构造函数不能是虚函数。
  • 另一个优点:实现封装。

3.内存分布

C/C++主要有五种内存存储区

  • 全局/静态存储区域:存全局变量静态变量。程序编译时内存已分配好,并存在于程序整个运行期间,程序结束后由系统统一释放
    全局变量和静态变量被分配到同一块内存中。
    C 语言中,全局变量又分为初始化的和未初始化的。初始化的全局变量和静态变量在一块区域,未初始化的全局变量与静态变量在相邻的另一块区域。同时未被初始化的对象存储区可以通过 void* 来访问和操纵,程序结束后由系统自行释放。
    在 C++ 里面没有区分,他们共同占用同一块内存区。

  • :存放函数的参数值局部变量由高到低分配。

    • 函数执行结束时会被自动释放。栈内存分配运算内置于处理器的指令集中,效率高,但是容量有限。
  • 动态内存分配):通过**new和malloc由低到高分配
    • 由delete或free手动释放或者程序结束自动释放**。动态内存的生存期人为决定,使用灵活。缺点是容易分配/释放不当容易造成内存泄漏,频繁分配/释放会产生大量内存碎片。 若程序员不释放,程序结束时可能由OS(操作系统)回收
  • 字符/文字常量区: 存放常量字符串,程序结束时由系统释放
  • 程序代码区: 存放函数体的二进制代码

4.static

  • 隐藏(static函数,static变量均可)
    作用:当前文件可用,不同文件可以定义同名函数和同名变量,不必担心命名冲突 ,static函数的作用仅限于隐藏
  • 保持变量内推的持久(static变量的记忆功能和全局生存期)
  • 默认初始化为0(static变量)
  • C++中
    • 属于类不属于对象
    • 必须类外定义,且定义的时候去掉static,如:void Father::a = 0;
    • static函数无this指针,只能访问static成员,但是非static成员函数因为具有this指针,可以访问static变量或函数,后者因为属于类成员函数,在this管控范围之内

5.程序编译过程

C++程序编译过程

6.智能指针

  • 智能指针是一个类,构造函数传入一个普通指针(explicit显式),析构函数释放传入的指针。智能指针的类都是栈上的对象,所以当函数(或程序)结束时会自动被释放。主要用来解决new对象忘记delete的危害
  • std::auto_ptr:转移所有权。 不支持复制(拷贝构造函数)和赋值( operator =),但复制或赋值的时候不会提示出错。因为不能被复制,所以不能被放入容器中。
  • unique_ptr,也不支持复制和赋值,但比 auto_ptr 好,直接赋值会编译出错。实在想赋值的话,需要使用:std::move 或者 右边是一个临时对象。
  • shared_ptr,基于引用计数。
  • weak_ptr,弱引用, 只引用,不计数。引用计数有一个问题就是互相引用形成环,这样两个指针指向的内存都无法释放。 weak_ptr 不保证它指向的内存一定是有效的,在使用之前需要检查 weak_ptr 是否为空指针。

7.extern

  • 外部变量声明
  • 多个文件共享const变量
  • extern ‘C’ C语言编译,但是重载函数只能有一个
  • 模板的控制实例化

8.volatile

  • 可能会发生意想不到的改变,直接从内存读取,不要从寄存器缓存中读

9.指针vs引用

  • 非空区别:引用必须指向某对象,指针可为空;
  • 合法性区别:指针可为空,所以用前要检查;
  • 指向可修改区别;
  • 指针要解引用;sizeof 结果不同;自增意义不同;引用不分配内存。

10.const vs #define

  • Const 有类型检查,安全。
  • define在预处理替换,const在编译时确定值
  • define不分配内存,用的地方多会发生多次拷贝,内存消耗大,const在静态存储区中分配空间,运行过程中内存中只有一个拷贝。
  • C++:const成员变量只能用初始化列表,引用也是。

11.sizeof vs strlen()

  • Sizeof是操作符,不是函数,返回的是变量声明后所占的内存数,不是实际长度。其值在编译时即计算好了,参数可以是数组、指针、类型、对象、函数等。当计算数组的size时,数组不会退化成指针
  • Strlen 是函数,strlen(char*)函数求的是字符串的实际长度,直到遇到第一个’\0’,然后就返回计数值,且不包括’\0’,函数的返回值值在运行时确定。参数是指针或字符数组,当数组名作为参数传入时,实际上数组就退化成指针了
#include <iostream>
#include <string.h>
using namespace std;

int main()
{
    char arr[20]="hello world!"; 
    cout<<"strlen(arr) : "<<strlen(arr)<<endl;  //返回12,一共有12个字符,不包括'\0'
    cout<<"sizeof(arr) : "<<sizeof(arr)<<endl;  //返回20,因为系统给数组分配了20个字节


    cout<<"strlen(\"hello\") : "<<strlen("hello")<<endl;  //返回字符串长度5
    cout<<"sizeof(\"hello\") : "<<sizeof("hello")<<endl;  //返回6,实际的存储空间还包含最后面的'\0'

    char *p="hello";
    cout<<"strlen(p) : "<<strlen(p)<<endl;  //返回字符串长度5
    cout<<"sizeof(p) : "<<sizeof(p)<<endl;  //返回指针p的内存空间大小4个字节
}

12.内存对齐

  • 自身对齐:地址为自身大小的整数倍;
  • 整体对齐:为最大成员的整数倍;

13.为什么要有继承

  • 清楚定义对象的特性,减少冗余代码;
  • 多态性;
  • 重用
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值