0%

C/C++

记录c++一些基础知识和面试常考点

语言基础


  • C++三大特性:封装、继承、多态
  • C++可复用性高,引入了模板的概念

struct和class区别

  1. struct一般用于描述一个数据结构集合,class是对一个数据对象的封装
  2. struct中的默认访问控制权限是public,class中默认访问控制权限是private
  3. 在继承关系中,struct默认公有继承,class默认私有继承
    • 公有继承:公有继承时,对基类的公有成员和保护成员的访问属性不变,派生类的新增成员可以访问基类的公有成员和保护成员访问不了私有成员。派生类的对象只能访问派生类的公有成员
    • 私有继承:基类的公有成员和保护成员都被派生类继承下来变成私有成员,派生类的新增成员可以访问基类的公有成员和保护成员,访问不了积累的私有成员。派生类的对象不能访问基类的任何成员

c++编译过程

  • 预编译
  • 编译
  • 汇编
  • 链接

预编译

  1. 删除所有的#define,展开所有的宏定义
  2. 处理所有的条件预编译指令,如#if、#ifndef
  3. 处理#include预编译指令,将被包含的文件插入到预编译指令的位置
  4. 过滤所有的注释
  5. 添加行号和文件名标识

编译

词法分析、语法分析、语义分析、代码优化、生成目标代码(汇编代码)、目标代码优化

汇编

将汇编代码变成机器可执行的指令

链接

将不同的源文件生成的目标文件进行链接,形成一个可执行的程序
分为静态链接动态链接

static关键字

  • 定义全局变量和静态变量,静态变量只能在本源文件中使用
  • 定义静态函数,静态函数只能在本源文件中使用
  • 定义类的静态成员变量
  • 定义类的静态成员函数

野指针

  • 概念:指向位置不可知的指针
  • 产生原因:释放内存后指针不及时置空,依然指向了该内存,可能出现非法访问的错误
  • 避免方法
    • 初始化置NULL
    • 申请内存后判空
    • 指针释放后置NULL
    • 使用智能指针

const和define的区别

const定义常量;define定义宏,也可以定义常量

  1. const生效于编译的阶段;define生效于预处理阶段
  2. const定义的常量储存在内存中、需要额外的内存空间;define定义的常量,运行时是直接的操作数,不会存放在内存中
  3. const定义的常量带类型;define定义不带类型

int const*和int *const的区别

  • int const* //指针的指向可变,内容不可变
  • int *const //指针的指向不可变,内容可变

c++内存


堆和栈的区别

  1. 堆栈空间分配不同:栈由操作系统自动分配释放,存放函数的参数值,局部变量的值等;堆一般由程序员分配释放
  2. 堆栈缓存方式不同:栈使用一级缓存,通常被调用时处于存储空间,调用完毕立即释放;堆则是存放在二级缓存中,速度慢些
  3. 堆栈数据结构不同

c++内存分配方式

  1. 从静态分区分配:此时的内存在程序编译时已经分配好,并在整个运行期间存在。全局变量,static变量在此存储
  2. 在栈区分配:相关代码被执行时创建,执行结束后自动释放
  3. 在堆区分配:动态分配内存,由程序员决定

常见内存错误

  • 内存未分配成功,却被使用。对策:使用内存前检查是否分配成功
  • 内存分配成功,未初始化就使用
  • 内存操作越界
  • 释放了内存,仍在使用。野指针
  • 未释放内存,导致内存泄露

内存泄露

申请了一块内存,使用完毕后没有释放。

面向对象


面向对象三大特征

  1. 封装:将数据和操作数据的方法有机结合,隐藏对象的属性和实现细节,使用公开接口和对象使用
  2. 继承:实现现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展
  3. 多态:用父类型别的指针指向子类的实例,通过父类的指针调用实际子类的成员函数。实现多态的两种方式:重写重载

重写和重载

  • 重写:是指派生类中存在被重新定义的函数。其函数名,参数列表,返回值类型,所有都必须和基类中被重写的函数一致。只有函数体不同,派生类对象调用时会调用派生类的重写函数,不会调用基类的函数。重写的基类中被重写的函数必须有virtual修饰
  • 重载:同一访问区内被声明的几个具有不同参数列的同名函数,根据参数列表确定调用哪个函数,重载不关心函数返回类型

构造函数

默认构造函数、初始化构造函数、拷贝构造函数、移动构造函数

  • 默认构造函数和初始化构造函数在定义类的对象时完成对象的初始化工作
  • 拷贝构造函数用于复制本类的对象
  • 移动构造函数用于将其他类型的变量隐式转换为本类对象

析构函数

只定义了析构函数,编译器将自动为我们生成拷贝构造函数和默认构造函数

向上转型和向下转型

  • 向上转型:子类转换为父类,使用dynamic_cast(expression),这种转换相对来说比较安全不会有数据的丢失
  • 向下转型:父类转换为子类,可以使用强制转换,不安全,会导致数据的丢失。父类的指针或引用的内存中可能不包含子类成员的内存

深拷贝与浅拷贝

  • 浅拷贝:值拷贝,本质上来说源对象和目标对象共用一份实体,只是所引用的变量名不同,地址含是相同的。
  • 深拷贝:拷贝的时候先开辟出和源对象大小一样的空间,然后将源对象的内容拷贝到目标对象中去。

c++11新特性


智能指针

  • auto_ptr
  • unique_ptr
  • shared_ptr
  • wear_ptr