编程之功(C++语言层次)

来源:互联网 发布:算法导论 百度云 编辑:程序博客网 时间:2024/04/27 23:23

     本索引列举C++语言层次上应注意的问题。持续保持更新。好多都是小弟自己总结出来的,想必有错误,若被发现,欢迎批评指出哇~~~


类相关:

  •  静态成员声明时必须包含static关键字,但定义时不得包含。
  •  Using改变类中函数或数据的访问权限
  •  如果虚继承,共同基类必须显式初始化;非虚继承不可越级初始化
  • Template类声明与定义应该在一个文件内。若要分开,则要在template前加export关键字
  • Private继承和protected继承属于has-a关系,不是is-a关系,因此基类指针和引用不能不经显式转换指向派生类对象
  • 声明类的特定具体化为template class<int>,而具体化(特化)为template<> class IC<int>
  • 基类总是早于派生类被初始化,总是晚于派生类被析构。
  • Class成员变量总是以其声明顺序初始化
  • 友元类不需要向前声明
  • 友元函数的声明可以是一个定义,友元类不可以

成员变量:

  • l类定义体中的所有变量都只是一个声明过程。所以,static成员变量需要在类外定义;引用成员变量需要在构造函数中初始化。
  • 类声明中,可以用static const来声明并初始化符号常量(只可用于intenum
  • Static成员变量初始化时可以调用私有的构造函数。(实现Singleton

成员函数:(非构造析构)

  •  默认参数可在实现或声明处定义,但不得同时定义。
  • 局部类
  • Virtual table是一个类一张表
  • Pointer to member function
  • 类函数声明后的const用来修饰this
  • 类方法和友元只是表达类接口的两种不同的机制
  • 转换函数必须是类成员函数,不能有返回类型,不能有参数,并且会在合适的情况下自动调用,不能用explicit限制
  • 派生类定义基类虚函数时,若参数不同,则不会发生重载,而是重新定义。
  • 派生类定义基类的虚函数时,允许返回值兼容不同,叫做返回类型协变
  • 如果基类虚函数被重载,则派生类要定义所有重载函数,否则未定义的会被隐藏
  • C++所有的类函数调用都会在内部转化为C函数,只是传入了this指针
  • 在类外定义模版类的函数,如果用到模版类型,也应加入template<class Type>前缀,内联定义不加

成员类型:

  • 类或结构体定义的enum类型,enum成员就被当成该类或结构体的常量成员
  • 在类中声明的结构、类、枚举,若为privateprotected,只能在类中使用;若为public,则可以在类外通过域解析操作符使用。
  • Friend用于类只能用于类原型的声明
  • 类中类可以直接访问上级类的名称、静态、枚举,天生具有友元类属性

编译器自动生成的类函数:

  • 若用户未定义,编译器会自动生成默认的=,无参构造函数,拷贝构造函数,析构函数
  • 带含有默认值参数的构造函数也是一种默认构造函数(不可以再定义一个无参构造函数)
  • 复制构造函数在以下情况下调用:函数按值传递对象、函数返回对象、4种复制赋值对象。
  • 默认复制构造函数是按值传递(浅拷贝)
  • 初始化器(构造函数初始化列表)分别调用列表中每个成员的构造函数进行成员初始化,调用顺序与声明顺序相同,与初始化顺序无关。这种格式(初始化列表)只能用于构造函数,必须用这种格式初始化非静态const和引用数据成员。
  • 派生类不能继承基类的构造函数、析构函数、赋值操作符
  • Explicit防止单参构造函数隐士转换
  • 对象的成员变量的初始化动作发生在进入构造函数本体之前
  • 类成员初始化顺序:基类早于派生类;class成员变量总以其声明次序被初始化
  • 如果某个基类的拷贝构造函数声明为private,派生类拒绝生成默认拷贝构造函数。
  • 所有编译器自动生成的函数都是public
  • 在基类构造期,virtual函数不是virtual函数(此时对象就是基类对象,RTTI也会这么显示)


通用编程相关:

  • Template表达式参数只可以是整数、枚举、引用或指针,并且必须是常量表达式,内部不可修改参数值,或取参数地址
  • 在模版句法中,维的顺序与等价的二维数组相反
  • 可以为类模版类型参数提供默认值,但不能为函数模版类型参数提供默认值。但都可以为非类型参数提供默认值
  • 若把模版声明和定义分开(无export),包含头文件进行实例化,则可能会通过编译,但不会通过链接。因为只实例化了声明代码,没有实例化定义代码
  • 包含模型可能会出现重复定义问题,但编译器的“贪婪实例化”机制会去除标记的重复定义代码,用户不需要考虑
  • 在代码中包含模版不会生成函数或类定义
  • 显式特化(偏)是一种重定义,显示实例化是基于原版的代码生成
  • 两个> >挨在一起(template时会出现),若不是>>要加空格
  • .template标记,在前面存在依赖于模版参数的对象时,才需要在模版内使用.template,并且该标记只能在模版内使用
  • 非显式实例化允许编译器产生重复代码(会自动标记删除),但显式实例化不可。不能重复显式实例化出相同的代码
  • 函数模版虽然声明和定义放在一起,但不一定是默认内联的,需要内联还是应该加上inline修饰
  • export只需加在声明前,定义可加可不加
  • export不可和inline连用
  • 模版的模版参数不能使用struct, union
  • 模版的模版参数只能被自身其他参数的声明使用
  • 局部累,局部enum不能作为模版类型实参;未命名class、enum也不能
  • 从函数模版产生(实例化)的函数一定不会等于普通函数
    • 从成员函数模版产生的函数一定不会改写一个虚函数
    • 从构造(赋值)函数模版产生的构造(赋值)函数一定不会是缺省的构造(赋值)函数

模版函数:

  • 只要调用模版函数,编译器会自动将模版实例化。若不指定实例化类型,编译器会自动推到出合适的类型
  • 自动推导的函数模版参数匹配时,不允许相容类型匹配同种类型(拒绝隐士转换),但显示实例化可以
  • 模版函数中,当模版参数和调用参数类型无关时,自动推导不可用,必须显式指定
  • 函数模版中,显式制定的自左向右,未指定的自动推导,推导不出来的报错
  • max<>(7,42),表示必须从模版函数匹配
  • 模版函数重载时,匹配顺序是:
    • 优先匹配能产生最精确匹配的函数
    • 都可以产生精确匹配的情况下,优先级如下:
      • 非模版函数
      • 特化版函数
      • 偏特化版函数
      • 模版函数
  • 重载函数的集合名称不能被用于模版参数演绎;函数模版实例通常被编译器看成一组重载函数的集合
  • 非引用类型字符串数组在实参演绎中会退化为指针,而引用类型不会
  • 不能在函数内部声明模版
  • 函数模版只可以是基本模版,即只可重载不可特化
  • typedef不会对实参的等价性匹配产生影响
  • 不能在类声明里特化模版函数,

模板类:

  • 只有那些被调用的成员函数会被实例化
  • 在特化模板类时,成员函数也必须被特化
  • 模版实参默认值可以引用之前的模版参数
  • 模版成员函数定义时要制定所有类模版类型
  • 非类型模版参数只可以是:整形(枚举也算)、引用、指针(普通指针、函数指针、成员指针)。但空指针常量、字符串除外
  • 派生模版类调用模版基类符号(函数、变量),必须用this->或Base<I>::修饰
  • 嵌套类和模版也可以是模版
  • 成员函数模版不能为虚
  • 普通类名和非类名称位于不同的名字空间,所以可以重复;模版类不可以
  • 缺省模版实参不能依赖于自身的参数,但可以依赖于前面的参数
  • 缺省模版实参不能重复声明;任何一个模版参数只有在之后的模版参数都提供了缺省实参的前提下,才能具有缺省模版实参
  • 可以命名一个特定模板类的实例为友元

类型相关:

  • Static_cast/reinterpret_cast/const_cast
  • RTTI:Dynamic_cast  必须用在基-子对象转换,必须是虚
  • 只要隐士转换单向可行,static_cast就双向可行。
  • reinterprete_cast不能将函数指针转化为数据指针

名称空间相关:

  • 在名称空间中声明的变量的作用域是整个名称空间
  • 函数的作用于可以是类或整个命名空间,但不能是局部的
  • 全局命名空间是名称空间的特例
  • 名称空间可以位于另一个名称空间中,但不能位于代码块中
  • 类名、struct、union、数据函数位于不同的名称空间,所以可以互相重复。
  • 在一个文件内定义namespace,则space外必须显式的使用namespace前缀
  • 如果定义的变量名要在其他文件中共享,则需要namespace保护,若只在本文件内使用,则不用namespace;类也是一种namespace,所以在类中也可
  • 命名空间里定义的变量,需要在cpp里定义在namespace里,也在h里extern在namespace里

其他:

  • Auto_ptr
  • Switchcase行只是行标签,不是选项之间的界限
  • 两个头文件不可以互相包含
  • 可以创建多个值相同的枚举量
  • 使用new[]来分配内存,必须使用delete[]来释放,使用new来分配内存,必须用delete释放,但NULL可用deletedelete[]
  • 自动存储对象的创建顺序与被删除顺序相反
  • 使用布局new创建的对象,必须要显式调用析构函数再收回空间。
  • 初始化列表只可以用于structarray
  • 初始化对象数组时,会先调用默认构造函数创建对象数组,然后分为调用{}内的构造函数生成临时对象,最后调用拷贝构造函数。
  • 非成员函数的名称的作用域不能是局部的。
  • 隐式类型转换在匹配重载函数时会引起二义性
  • Extern "C"只能用于修饰声明,不能用于修饰代码块
  • New后面可以只写类名,这样会调用默认构造函数;写出具体()调用指定构造函数
  • 允许在程序中出现完全相同的多次拷贝:函数原型、#defineconst等符号常量、结构体、类、模版声明、内联函数。
  • 不允许在程序中出现多次的:函数定义、变量定义、对象定义
  • 要给一个函数参数默认值,必须给后面所有参数默认值
  • 只能使用常量表达式来初始化静态变量
  • Mutable可用于const结构体部分的非const处理
  • 全局const为内部链接,若加extern变为外部链接,且only此时,extern后可初始化,也必须初始化
  • 定义静态函数,声明和定义都必须加上static
  • 单定义规则:对于非内联函数,程序中只能有一个定义;内联同函数所有定义必须相同。
  • 若定义了一个与库函数同名的函数,则库函数被隐藏
  • Struct只有在不定义构造函数时,会被当成POD(可{}初始化)
  • 不能在case语句中定义变量。可在siwtchcase之间。
  • 函数在实参类型不正确,但可转化为正确类型时;实参类型正确,但不是左值时创建临时对象。但若形参非const引用会报错。
  • 引用是已定义变量的别名:
    • 必须在创建时初始化
    •  引用无法用常量和临时对象初始化
    • 在函参传递引用时,仅当参数为const引用时,会创建参数的临时对象
    • 初始化引用的必是左值
    • 数组不可以用引用
  • 全局强符号、弱符号
    • 函数和初始化了的全局变量为强符号;未初始化的全局变量为弱符号。
    • 不允许强符号重复定义;
    • 如果一个符号在一个文件中为强符号,其他文件中为弱符号,选择强符号;
    • 如果一个符号在所有目标文件中都是弱符号,选择占空间最大的一个

  • 两个函数如果只是常量性不同,可以被重载
  • C++不保证两个编译单元中的全局变量的初始化顺序
  • C++不允许让reference改指不同对象
  • New先分配空间,再在该空间调用构造函数,delete先调用析构函数,再收回空间。In-place new直接在place调用构造函数,不分配空间。
  • case里的{}中可以定义变量。
  • inline和reigister只是一种请求,编译器会自己决定要不要采用
  • 友元声明可以位于共有、私有或保护部分,其所在位置无所谓
  • 在发生异常时,会发生堆栈解退
  • int(),float()可以调用内部基本类型的构造函数来初始化为0
  • new数组不要写成new初始化(用[]不用())

STL

  • Set可选排序方式,若set为自定义对象,必须提供相应的比较操作符重载,默认为<

操作符:

  •  操作符重载至少有一个操作数是用户定义的类型,不能违反操作符原来的句法。
  • 不能定义新的操作符
  • 不是所有的操作符都可以重载。()[]->只可以作为类的成员函数重载 
  • ::表示全局限定符,取得是全局标识符



原创粉丝点击