C++ note

字节对齐

#pragma pack的n值等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果。
VS默认```#pragma pack(8)```,gcc默认```#pragma pack(4)```

命名的强制类型转换:

* static_cast(无底层const)
* dynamic_cast(运行时类型识别)
* const_cast(有底层const)
* reinterpret_cast(低层的重新解释)

1. static_cast:与reinterpret_cast的区别, 在父子类指针转换时,会计算偏移量

2. dynamic_cast: 将父类对象指针(引用)cast到子类, 会根据父类指针是否真正指向父类来做处理

3. const_cast: const指针(引用)指向非const对象, 通过const_cast转为非const指针(引用)

4. reinterpret_cast: 转换前与转换后的指针在数值上相同

const

1)const对象

  • const对象必须初始化,因为创建后const对象的值就不能再改变,初始值可以是任意复杂的表达式
    const int i = get_size(); //运行时初始化
    const int j = 42;         //编译时初始化
    
  • 只能在const类型的对象上执行不改变其内容的操作
  • 当以编译时初始化的方式定义一个const对象时,编译器将在编译过程中把用到该对象的地方替换成对应值
  • 默认状态下,const对象仅在文件内有效。多个文件的同名const对象等同于在不同文件中定义了独立的变量
  • 要在多个文件之间共享同一个const对象,需在定义和声明时都加上extern

2)const的引用(常量引用)

  • 不能修改所绑定的对象
  • 和非常量引用不同,常量引用可以使用字面值或任意表达式作为初始值(原因:绑定了一个临时量常量)

3)指针与const

  • 指向常量的指针(并不一定要指向常量,只是为了说明无法修改所指的对象)
    const int *a = &b;
    
  • const指针(常量指针):不能修改指针,将一直指向一个地址,因此必须初始化。但是指向的对象不是常量的话,可以修改指向的对象
    int *const a = &b;
    const double *const pip = π //pip是一个常量指针,指向的对象是一个双精度浮点型常量
    

4)顶层const与底层const

  • 顶层const:无法修改指针本身(顶层是一种直接的关系)
    const int ci = 123; 
    int *const a = &b;
    
  • 底层const:无法修改所指的对象(底层是一种间接的关系)
    • 用于声明引用的const都是底层constf

重载、覆盖与虚函数的区别

  1. 成员函数重载特征:
    a 相同的范围(在同一个类中)
    b 函数名字相同
    c 参数不同
    d virtual关键字可有可无

  2. 重写(覆盖)是指派生类函数覆盖基类函数,特征是:
    a 不同的范围,分别位于基类和派生类中
    b 函数的名字相同
    c 参数相同
    d 基类函数必须有virtual关键字

  3. 重定义(隐藏)是指派生类的函数屏蔽了与其同名的基类函数,规则如下:
    a 如果派生类的函数和基类的函数同名,但是参数不同,此时,不管有无virtual,基类的函数被隐藏。
    b 如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有vitual关键字,此时,基类的函数被隐藏。

static与extern

  1. C++与C中,static的区别(存储地址、生命周期、作用域、C++多了静态数据成员和静态成员函数)
  2. static有哪些作用
  3. extern

模板

模板编译

  • 遇到模板时不生成代码,实例化时生成代码
  • 函数模板和类模板成员函数的定义通常放在头文件中
  • 实例化冗余:当模板被使用时才会进行实例化这一特性意味着,相同的实例可能出现在多个对象文件中。当两个或多个独立编译的源文件使用了相同的模板,并提供了相同的模板参数时,每个文件中就都会有该模板的一个实例

1 实例化声明

形式:extern template declaration

extern template class Blob<string>;
extern template int compare(const int&,const int&);

当遇到extern模板声明时,不会在本文件中生成实例化代码。将一个实例化声明为extern就表示承诺在程序其他位置有该实例化的一个定义。对于一个给定的实例化版本,可能有多个extern声明,但必须只有一个定义

  • 实例化声明可以有多个:即多个源文件可能含有相同声明
  • 实例化声明必须出现在任何使用此实例化版本的代码之前。因为编译器在使用一个模板时会自动对其实例化

2 实例化定义

template declaration
template int compare(const int &,const int&);
template class Blob<string>;
  • 类模板的实例化定义会实例化该模板的所有成员
  • 所用类型必须能用于模板的所有成员:与处理类模板的普通实例化不同,编译器会实例化该类的所有成员。即使我们不使用某个成员,它也会被实例化。因此,我们用来显式实例化一个类模板的类型,必须能用于模板的所有成员

ODR原则

  • inline函数、constexpr函数通常定义在头文件中

类类型、枚举类型、具有外部连接的 inline 函数、具有外部连接的 inline 变量 (C++17 起)、类模板、非静态函数模板、类模板的静态数据成员、类模板的成员函数、模板部分特化、概念 (C++20 起),在程序中可以出现多个定义,只要每个定义都出现于不同的翻译单元中,且满足下列条件:

  • 每个定义都由相同的记号(token)序列构成(典型情况下是在同一个头文件中)
  • 每个定义内进行的名字查找(在重载决议后)都找到相同实体,但具有内部连接或无连接的常量可以指代不同的对象,只要不 ODR 式使用它们,并在它们在各个定义中都具有相同的值即可。
  • 重载运算符(包括转换,分配和解分配函数),在各个定义中都代表相同的函数(除非它们代表的是在这个定义中所定义的函数)
  • 它们具有相同的语言连接(比如包含文件时并未处于某个 extern "C" 块之中)
  • 以上三条规则同样适用于各个定义中的每个默认实参
  • 若该定义调用了带有前条件( [[expects:]] )的函数,或是包含断言( [[assert:]] )或带有契约条件( [[expects:]] 或 [[ensures:]] )的函数,则在何种条件下必须用同一构建等级和违规持续模式翻译所有定义,是由实现定义的
    (C++20 起)
  • 若该定义是带有隐式声明的构造函数的类定义,则在每个 ODR 式使用它的翻译单元中,必须为基类和成员调用相同的构造函数
  • 若该定义是模板定义,则所有这些要求一同适用于定义点的各个名字和实例化点的各个待决名

概览

  非模板类型(none-template) 模板类型(template)
头文件(.h)
  • 全局变量申明(带extern限定符)
  • 全局函数的申明
  • 带inline限定符的全局函数的定义
  • 带inline限定符的全局模板函数的申明和定义
  • 类的定义
  • 类函数成员和数据成员的申明(在类内部)
  • 类定义内的函数定义(相当于inline)
  • 带static const限定符的数据成员在类内部的初始化
  • 带inline限定符的类定义外的函数定义
  • 模板类的定义
  • 模板类成员的申明和定义(定义可以放在类内或者类外,类外不需要写inline)
实现文件(.cpp)
  • 全局变量的定义(及初始化)
  • 全局函数的定义
(无)
  • 类函数成员的定义
  • 类带static限定符的数据成员的初始化


可重入函数

重入发送于 1. 多个线程同时执行该函数 2.函数自身(可能是经过多层调用后)调用自身
可重入函数:

  1. 不使用任何(局部)静态或全局的非const变量
  2. 不返回任何(局部)静态或全局的非const变量的指针
  3. 仅依赖于调用方提供的参数
  4. 不依赖任何单个资源的锁(mutex等)

C++11特性

4个智能指针

  • auto_ptr:
  1. 不能指向数组,这是因为其内部实现,在析构函数里执行了delete ptr,而不是delete[] ptr。
  2. 不可能存在多个auto_ptr指向同一个对象。这是最主要的原因。也就是说,auto_ptr不能用作STL容器的元素。
  • unique_ptr
  • shared_ptr
  • weak_ptr: 指向由一个shared_ptr管理的对象。将weak_ptr绑定到shared_ptr不会改变shared_ptr的引用计数。

constexpr与常量表达式

  • constexpr变量(C++11):变量声明为contexpr类型,编译器会检查变量的值是否是个常量表达式
    constexpr int mf = 20          //20是常量表达式
    constexpr int limit = mf + 1;  //mf + 1是常量表达式
    const int sz = size();         //只有当size是一个constexpr函数时,声明才正确
    
  • constexpr函数:这种函数足够简单以使编译时就可以计算其结果
  • 字面值类型:能使用constexpr声明的类型应该足够简单,称为字面值类型
    • 包括
      • 算数类型
      • 引用 & 指针
        • constexpr的指针初始值必须是nullptr,0或存储于某个固定地址中的对象
        • 一般来说全局变量和静态局部变量的地址不变
        • constexpr指针,constexpr只对指针有效,与指针所指对象无关
        • constexpr const int *p = &i //p是常量指针,指向整形常量i
    • 不包括
      • 自定义类型
      • I/O 库
      • string字符串

static、extern、volatile(1. 阻止编译器为了提高速度将变量缓存到寄存器而不写回, 2. 阻止编译器调整操作volatile变量的指令顺序(阻止CPU乱序优化需要使用CPU提供的barrier指令) )、mutable(只能由于修饰类的非静态数据成员,const函数可以修改mutable成员变量)

move、lambda、tuple、bitset、explicit(防止类构造函数的隐式自动转换)、=default、=delete、引用折叠

posted @ 2019-10-10 22:05  我在地狱  阅读(415)  评论(0编辑  收藏  举报