C++ 开发随笔

基础

多态

  • “一个接口,多个实现”:通过父类调用子类的成员,实现了接口重用,如父类的指针指向子类的对象
  • 编译多态:函数重载 函数模版
  • 运行多态:派生类对象的地址可以赋值给基类指针。对于通过基类指针调用基类和派生类中都有的同名、同参数表的虚函数的语句,编译时并不确定要执行的是基类还是派生类的虚函数;而当程序运行到该语句时,如果基类指针指向的是一个基类对象,则基类的虚函数被调用,如果基类指针指向的是一个派生类对象,则派生类的虚函数被调用。这种机制就叫作多态
  • 多态如何实现:虚函数表存储在代码段上,一个类的不同对象共用一个虚函数表。先构建一个基类,然后在基类的构造函数中建立虚函数表,也就是一个储存虚函数地址的数组,内存地址前四个字节保存指向虚函数表的指针,当子类继承父类后,主函数可以通过父类指针调用子类的继承函数
  • 多态的本质:基类的引用,指针指向谁,就去谁的的虚函数表中找到对应的虚函数调用
  • 定义的父类指针new出哪个子类就是指向哪个子类的虚函数。

父类构造函数是否可以调用虚函数

可以,不过会屏蔽多态机制,最终会把基类中的该虚函数作为普通函数调用,而不会调用派生类中的被重写的函数

虚函数

  • 析构函数一般写成虚函数 如果不这样 删除指向子类的父类指针时 编译器只会调用父类析构函数 造成内存泄漏
  • 构造函数不定义为虚函数 创造一个对象需要确定对象类型,虚函数是运行时确定类型的;对象未创建时也没有虚函数表
  • 纯虚函数 只有声明没有实现 包含他的类是抽象类
  • 静态函数不可以是虚函数,因为静态成员函数没有this,没有存放vptr的地方;它是编译的时候确定的
  • 包含纯虚函数的类称为抽象类

静态绑定 动态绑定

  • 静态绑定也就是将该对象相关的属性或函数绑定为它的静态类型,也就是它在声明的类型,在编译的时候就确定。在调用的时候编译器会寻找它声明的类型进行访问
  • 动态绑定就是将该对象相关的属性或函数绑定为它的动态类型,具体的属性或函数在运行期确定,通常通过虚函数实现动态绑定

拷贝

  • 浅拷贝 复制指针 指向同样的资源
  • 深拷贝 新开辟空间 复制资源
  • 零拷贝 避免来回拷贝

C和C++区别

  • 结构不同 结构体 只能定义变量 不能定义函数
  • 设计不同 面向过程 面向对象 C++ 封装 继承 多态 强制类型转换 模版类 函数模版
  • 内存管理方法 new malloc
  • Struct
    C中不能声明函数、不能访问控制符
    C++中默认访问控制是public

动态链接库

  • DLL,包含函数和数据的模块,可以被其他模块(应用或者DLL 使用
  • 导出函数和内部函数
  • DLL提供了一种模块化应用程序的方法,以便功能更新和重用、减少内存占用(每个程序需要拥有属于自己的DLL数据副本,但共享DLL代码
  • 与静态链接不同,允许在载入时或运行时确定DLL导出函数
  • 种类
    载入时的动态链接
    运行时的动态链接
  • DLL中的数据
    可以包含全局数据和局部数据
    每个载入给定DLL的进程都会有属于它自己的DLL全局变量和静态变量实例

malloc和new

  • Malloc 堆上动态分布内存 分配失败抛出异常
  • New 分配内存空间为自由存储区 无需指定大小 会调用构造 析构函数
  • malloc 库函数
  • New 关键字
  • 自由存储是通过new delete动态分配和释放对象的抽象概念
  • New失败抛出bad_alloc异常
  • malloc需要指定内存大小,new无需指定

New operator和operator new区别

new就是new operator,调用new时编译器先用operator new分配内存,再调用构造函数,最后返回相应指针
Placement new:保存一块内存,反复构造析构,这样可以省略中间的多次分配内存

防止编译器在栈上为类对象分配内存

如果类的析构函数是私有的,则编译器就不会在栈上为类对象分配内存了
可以将析构函数和构造函数用protected形式,然后提供一个public的static的函数完成构造
只有使用new运算符,对象才会建立在堆上,因此,只要禁用new运算符就可以实现类对象只能建立在栈上。将operator new()设为私有即可

智能指针

auto_ptr
shared_ptr 有use_count 避免内存泄漏
一个对象可以有多个智能指针,当这个对象所有的智能指针被销毁时就会自动进行回收。
use_count(追问) 对象数据的引用计数,每次引用计数加1,每次释放计数减一
unique_ptr 资源只能被一个指针占有 std::move可以实现所有权的转移
weak_ptr 指向shared_ptr指向的对象,解决循环引用(两个类相互引用导致无法释放)的问题
观测shared_ptr引用计数 防止死锁

智能指针和普通new指针主要区别是作用范围上的区别

重载和重写区别

重载(overload)是指函数名相同,参数列表不同的函数实现方法。它们的返回值可以不同,但返回值不可以作为区分不同重载函数的标志。
重写(override)是指函数名相同,参数列表相同,只有方法体不相同的实现方法。一般用于子类继承父类时对父类方法的重写。子类的同名方法屏蔽了父类方法的现象称为隐藏。
覆盖:子类对基类的方法进行覆盖,但是能够调用基类的方法,且子类能添加自己的内容

重载为什么改变参数就可以实现调用不同的函数?

C++编译的时候会对函数重命名。保证函数名的唯一性,参数不同就会被命名为不同函数名
构造函数可以被重载,因为构造函数有多个且可以带参数
析构函数不可以被重载

内存管理

堆 类似链表 容易产生碎片 效率低
栈 自动分配释放 存放局部变量 返回数据 返回地址等
全局区 存放全局变量 静态变量 常量
常量区 文字常量区 存放常量字符串
代码区

关键字

define const
预处理阶段替换/编译阶段替换
不会进行类型安全检查
Define占用内存空间大
inline 展开
Volatile 值十分容易改变 不会对他优化
C11
auto
nullptr
lambda
thread
mutex
shared_ptr

Explicit 防止类构造函数的隐式自动转换,只用于类内单参数构造函数前面
const
放在函数前 限制函数返回类型为指针时通过指针修改返回值
函数后 限制类中的成员函数
static

修饰全局变量 只对定义在同一文件中的函数可见
局部变量 表明该函数值不会因为函数丢失而终止
修饰函数 表明该函数只在同一文件中调用
C++独有:修饰类的数据成员 该实例归所有对象共有;修饰类成员函数 只能访问他的参数
类静态数据成员 全局变量
静态成员属于整个类 而不属于某个对象

左值 右值

左值:可寻址的表达式 即可以使用&
右值:只读表达式 临时值
右值引用:解决临时对象非必要的昂贵拷贝操作
const修饰的左值引用可以引用右值

lambda表达式

捕获列表 参数列表 可变规则 返回类型 函数体
[=] (int x, int y) -> bool {return x < y;}

构造函数

默认
重载 一般构造函数 自定义
拷贝 对象复制 以值传递方式传入 以值传递方式从函数返回 通过另一个对象进行初始化
成员初始化列表:直接使用传入参数的拷贝构造函数初始化 省去一次默认构造函数过程
构造函数调用:基类构造函数 对象成员构造 派生类本身构造
析构函数调用:反过来

避免对象的拷贝
如果要使某个类不具备拷贝的功能,可以写一个基类,然后将拷贝构造函数声明为private且不去实现它,或者将拷贝构造设置为delete

你可能感兴趣的:(开发随笔,c++,java,开发语言)