> 文章列表 > C++基础学习

C++基础学习

C++基础学习

文章目录

  • 编译内存相关
    • 编译
    • 变量与内存分区
    • 内存对齐
    • 内存泄露
    • 智能指针
    • include "" 和<>
  • 语言对比
    • c++ 11
      • 自动类型推导
      • lembda 表达式 (匿名函数
      • 范围for
      • 右值引用 与 std::move()
    • delete 函数和 default 函数
    • 对比C、python
  • 面向对象
    • 特性
    • 重载、重写、隐藏的区别
  • 关键字和库函数
  • 类相关
    • 虚函数 与 纯虚函数
    • 虚函数实现机制
    • 单继承多继承的虚函数表结构

参考:

  1. https://blog.csdn.net/luanfenlian0992/article/details/118771472#t13
  2. https://zhuanlan.zhihu.com/p/335994370

编译内存相关

编译

编译.cpp .h过程分为四个过程:编译(编译预处理、编译、优化.s),汇编.o,链接。

静态链接
动态链接

变量与内存分区

内存分区

  1. 栈区:
    正常函数体内{}"定义的都是。
    连续内存。

  2. 堆区:
    new出来的。
    类似链表的分段内存。

  3. 全局/静态存区:
    static和全局变量extern.

  4. 常量区:
    常量。

  5. 代码区:
    编译后的二进制文件。

变量类型

  1. 全局变量:
    放在.cpp文件里面的,不再{}内的变量,同样的名称多文件共享。
    多个cpp文件共用或者{}内使用需要extern修饰声明。

  2. 静态全局变量:
    static修饰,具有文件作用域,多个文件同样的名称是不同的变量。

  3. 局部变量:
    {}里面定义的。

  4. 静态局部变量:
    static修饰的{}函数中的变量,具有函数作用域,只初始化一次。

内存对齐

对齐存取快,不报异常好迁移。
有些设备不支持非对齐的存取,不能保证原子操作。

内存泄露

new出来的内存,由指针进行操作,后来没delete指针指向别的了,之前的那块内存地址就找不到了,没法删除啥的。

智能指针

智能指针,自动释放内存,防止内存泄露。

  1. shared_ptr
    多个指针共享一块内存,通过引用计数自动释放。

  2. unique_ptr
    一个指针独占一块内存,不能拷贝赋值。可以移动构造和移动赋值构造。

  3. weak_ptr
    指向 shared_ptr 指向的对象,能够解决由shared_ptr带来的循环引用问题。

include “” 和<>

https://www.iteye.com/blog/kooyee-340846解释:
<>先去系统目录中找头文件,如果没有在到当前目录下找。所以像STL标准的头文件 stdio.h、stdlib.h等用这个方法。

""首先在当前目录下寻找,如果找不到,再到系统目录中寻找。 这个用于include自定义的头文件,让系统优先使用当前目录中定义的。

语言对比

c++ 11

自动类型推导

  1. auto
auto var = val1 + val2; //定义+初始化为左边的值
  1. decltype
decltype(val1 + val2) var1 = 0; //定义+初始化为其他值

lembda 表达式 (匿名函数)

[capture list/*捕获的局部变量列表*/] (parameter list/*形参*/) -> return type/*返回变量类型*/
{/*具体函数实现*/function body;
};

范围for

for (declaration /*列表中的一个元素*/: expression/*列表、数组*/){statement
}

这玩意不和python的for差不多吗,多了个declaration的变量类型常用auto

右值引用 与 std::move()

右值引用可以修改右值,借助 std::move()转换引用左值

int &&a = 10;
a = 100;
int b = 5;
int &&refb=std::move(b);

https://zhuanlan.zhihu.com/p/335994370总结的右值引用好处

  1. 从性能上讲,左右值引用没有区别,传参使用左右值引用都可以避免拷贝。
  2. 右值引用可以直接指向右值,也可以通过std::move指向左值;而左值引用只能指向左值(const左值引用也能指向右值)。
  3. 作为函数形参时,右值引用更灵活。虽然const左值引用也可以做到左右值都接受,但它无法修改,有一定局限性。

delete 函数和 default 函数

  1. delete 函数:= delete 表示该函数不能被调用。
  2. default 函数:= default 表示编译器生成默认的函数,例如:生成默认的构造函数。
#include <iostream>
using namespace std;class A
{
public:A() = default; // 表示使用默认的构造函数~A() = default;	// 表示使用默认的析构函数A(const A &) = delete; // 表示类的对象禁止拷贝构造A &operator=(const A &) = delete; // 表示类的对象禁止拷贝赋值
};
int main()
{A ex1;A ex2 = ex1; // error: use of deleted function 'A::A(const A&)'A ex3;ex3 = ex1; // error: use of deleted function 'A& A::operator=(const A&)'return 0;
}

对比C、python

  • C++:面向对象
  • C:面向过程
    • 没有bool类型,用int代替
  • python:解释执行

面向对象

特性

  1. 封装:将对象的数据和过程绑定在一起则被称为封装。
  2. 继承
  3. 多态:子类重写父类的virtual虚函数实现。

重载、重写、隐藏的区别

  1. 重载:
    就是函数的重载,和面向对象没关系

  2. 隐藏:
    子类的同名函数会隐藏父类的同名函数,如果需要调用父类函数需要.Base::fun()

  3. 重写(覆盖):虚函数,纯虚函数(子类一定要重写)
    父类的函数有virtual修饰,函数名、参数列表、返回值类型需要一致。
    主要应用:父类指针指向new子类对象,实现父类指针调用子类的函数。

关键字和库函数

这玩意太多了还是直接看别人写的吧

  1. explicit:避免编译器进行隐式类型转换
  2. static
    1. 修饰类内的变量函数时候,可以不创建类对象直接使用,不能定义为virtual函数。只能访问static成员。因为静态成员函数没有 this 指针。
    2. 静态数据成员的类型可以是所属类的类型,而普通数据成员的类型只能是该类类型的指针或引用。
  3. const:修饰常量不能更改,只能初始化时候赋值。mutable???
  4. #define:在编译预处理阶段进行文本替换
  5. typedef:定义类型的别名
  6. inline:内联函数。
  7. deletedelete[]
  8. new mallocdeletefree :malloc、free 是库函数,而new、delete 是关键字
    1. new:内存分配成功,返回该对象类型的指针;分配失败,抛出 bac_alloc 异常。申请空间时,无需指定分配空间的大小,编译器会根据类型自行计算;申请空间时,返回的类型是对象的指针类型,无需强制类型转换,是类型安全的操作符;
    2. malloc:成功申请到内存,返回指向该内存的指针;分配失败,返回 NULL 指针。在申请空间时,需要确定所申请空间的大小。申请空间时,返回的是 void* 类型,需要进行强制类型的转换,转换为对象类型的指针。
    3. 对于自定义的类型,new 首先调用 operator new() 函数申请空间(底层通过 malloc 实现),然后调用构造函数进行初始化,最后返回自定义类型的指针;delete 首先调用析构函数,然后调用 operator delete() 释放空间(底层通过 free 实现)。malloc、free 无法进行自定义类型的对象的构造和析构。
    4. new 操作符从自由存储区上为对象动态分配内存,而 malloc 函数从堆上动态分配内存。(自由存储区不等于堆)
  9. malloc 的原理?malloc 的底层实现?
  10. C 和 C++ struct 的区别?为什么有了 class 还保留 struct?
  11. union:联合体,只有一个有效的成员,对联合体的不同成员赋值,将会对覆盖其他成员的值,联合体的大小为其内部所有变量的最大值,按照最大类型的倍数进行分配大小。
  12. class 和 struct 的异同
    1. class(private 继承),struct(public 继承)
    2. class 可以用于定义模板参数,struct 不能用于定义模板参数。
  13. volatile:多线程巴拉巴拉的,类似线程锁。
  14. extern:C 语言编写的函数
  15. sizeof(1==1) 在 C 和 C++ 中分别是什么结果?
  16. memcpy 函数的底层原理?
  17. strcpy 函数有什么缺陷?

14.-17.啥的从来没用到过QAQ

类相关

虚函数 与 纯虚函数

  1. 虚函数必须实现,否则编译器会报错;
  2. 包含纯虚函数virtual fun()=0;的类为抽象类不能实例化对象。
  3. 子类继承抽象类,没有完全重写纯虚函数,也是抽象类。

虚函数实现机制

类的对象存储指向虚函数表的指针实现

  • 虚函数表
    1. 虚函数表存放的内容:类的虚函数的地址。
      
    2. 虚函数表建立的时间:编译阶段,即程序的编译过程中会将虚函数的地址放在虚函数表中。
    3. 虚表指针保存的位置:虚表指针存放在对象的内存空间中最前面的位置,这是为了保证正确取到虚函数的偏移量。

单继承多继承的虚函数表结构