07
-
定义在类内部的函数是隐式的inline函数 06函数一章说了建议在定义处增加inline关键字
-
this是一个指向类类型的非常量版本的常量指针
所以this不能绑定到一个常量对象上 所以不能再常量对象上调用普通的成员函数
所以在成员函数的列表之后加上const关键字 表示this是一个指向常量的指针
像这样使用const的成员函数被称作常量成员函数
所以常量对象只能调用常量成员函数 -
首先编译成员声明 再编译函数体 所以函数体可以随意使用类中的其他成员而无需在意其出现次序
-
声明中使用的名字 包括形参中的名字都必须在使用前确保可见
-
可以使用typedef或者using定义类类型成员
如上所述 类型成员的定义必须出现在使用之前
-
不能重定义类型 比如外部已经typedef int a 则在类内部不能重定义a
是变量的话则可以 因为内部的隐藏外部的 在这种情况下 可以使用作用域运算符::
强制访问 -
通常定义类类型成员 一般放在类的开始部位
-
-
常量成员函数必须
声明
和定义
都写cosnt -
IO类属于不能被拷贝的类型 所以只能用引用传递 因为读取和写入会改变流的状态 所以一般是普通引用
-
一般执行任务的输出的函数尽量减少格式控制 让用户代码决定如何换行或者排版
-
构造函数
与类名相同 没有返回类型 -
构造函数不能被声明为const (猜的 要是构造函数被声明为const怕是初始化也完成不了 哈)
当创建一个cosnt的对象时 直到构造函数完成初始化 对象才能获得其常量
属性 所以在const的构造函数中才可以向其写值 -
委托构造函数
委托构造函数也有初始化列表和函数体 但是函数体只能是另一个初始化函数
哈 就是将构造过程委托给另一个构造函数 例子如下struct T { int a = 4; int b = 7; int c; T(int _a, int _b, int _c) : a(_a), b(_b), c(_c) { } T(int _a) : T(_a, 0, 0) { } }; int main() { const auto t = T(1); cout << t.a << endl; cout << t.b << endl; cout << t.c << endl; return 0; }
-
默认构造函数
如果存在类内初始值 则用其初始化
否则就默认初始化 -
在c++11中如果你需要默认的构造函数 可以在参数列表后面使用
=default
来要求编译器生成默认构造函数
=default
即可以出现在类的内部也可以出现在类的外部都行 -
初始化列表
-
某个数据成员不在初始化列表中时 他将与以合成默认构造函数相同的方式隐式初始化
所以会用类内初始值初始化 没有类内初始值默认初始化可能未定义 -
初始化列表的初始化顺序是在类中定义的顺序一致
-
-
vector
对象或者数组
对象或者string
对象销毁时 存储在其中的对象也会被销毁 -
class和struct唯一的区别就是默认的访问权限 class默认访问权限private struct默认访问权限public
-
可变数据成员 mutable 关键字 比如 mutable int a 即使在const常量成员函数中 此变量也可以修改
mutable只能修饰类的非静态成员
通常可以用于修饰一些与类数据本身
无关的一些信息状态
然后可以在const常量成员函数中进行修改 即不影响类内本身数据又可以跟踪一些信息 -
类的声明
class Screen;
-
在声明之后定义之前 这是一个不完全类型 因为没有定义 所以无法创建这个类的对象
只能使用该类的指针或者引用 或者声明(但是不能定义 因为这个不完全类还没有定义
)以该类型作为参数或者返回值的函数 -
以上 无法在类的成员函数中无法使用类自己 但是可以是类的引用或者指针
-
-
默认构造函数在对象被默认初始化或者值初始化时执行
-
默认初始化在什么情况发生
-
在块作用域内不使用用初始值定义一个非静态变量
-
类本身含有类类型成员且使用合成的默认构造函数
-
类类型的成员没有出现在构造函数初始化列表中显示的初始化也咩有类内初始值时
-
-
值初始化在什么情况下发生
-
数组初始化时提供的数量少于数组大小时
-
不使用初始值定义局部静态变量
-
书写T()类似的形式显示表达值初始化 比如vector<int> a(10); 这样也是值初始化
-
-
-
接受一个参数的构造函数 实际定义了一种转换为此类的一种隐式转换 这个自动转换编译器只会执行
一步
可以通过增加 explicit 对这种隐式的自动转换加以阻止explicit
只能在类内的构造函数声明处出现 -
字面值常量类
-
之前接触到的字面值类型有
算数类型 引用 指针
-
什么是聚合类
-
全public成员
-
没有定义构造函数
-
没有类内初始值
-
没有基类 没有virtual
-
-
数据成员都是字面值类型的聚合类就是字面值常量类
-
具备以下要求的类也是字面值常量类
-
数据成员都是字面值类型
-
至少有一个constexpr构造函数
constexpr函数要求只允许有一条return语句 构造函数要求没有返回值 所以一般constexpr函数是空函数体 -
如果一个数据成员含有类内初始值 则内置成员的初始值必须是常量表达式
如果恰巧成员属于类类型(根据第一点 也就是字面值常量类本身哈哈)
那必须用其所属类的constexpr构造函数初始化 -
类必须使用默认的析构函数
-
-
-
类的静态成员
-
static关键字只能在类内的声明处出现
-
因为静态的数据成员不属于任何一个类的对象 所以一般来说不能在类的内部初始化静态成员
相反 必须在类的外部定义和初始化每个静态成员 -
所以通常类的静态成员会与类的非内联函数定义在一个文件中
-
比如
double Account::static_xxx = some_private_func_is_ok
类Account静态成员xxx初始化时是可以使用Account的私有函数的 因为从类名开始就是类的作用域啦啦 -
静态成员可以做默认实参
-
静态成员的类内初始值
-
给静态成员类内初始值时必须静态成员是constexpr的 初始值必须是常量表达式了
-
如果用到这个带初始值的静态成员的应用场景全部都是编译器可以替换的情况 那么可以不需要单独定义
如果有其他地方不能替换的地方用到了 比如形参const int&时 没有定义的话就会报错 -
所以就算有类内初始值也可以提供一个不带初始值的静态成员定义
struct T { // 类内初始值 不是定义 constexpr static int a = 20; }; //不带初始值的定义 constexpr int T::a;
-
-
-
友元 ----------------------
-
友元的声明仅仅是指定了访问权限 而非一个通常意义上的函数声明
如果我们希望类的用户可以调用某个友元函数 那么必须在友元之外专门对函数进行一次声明 -
为了使友元对用户可见 通常把友元的声明和类放在同一个头文件中
-
很多编译器并不要求在使用友元之前在类的外部声明 但是即使编译器支持这样 也还是建议为友元函数提供一个单独的声明
-
友元声明只能出现在类定义的内部 但是类内具体出现的位置不限 通常在类定义的开始或者结束集中友元声明
-
友元可以定义在类的内部 这样的函数同理也是隐式内联的
-
有函数重载时 如果一个类想把
一组重载函数
当作友元 需要对每一个重载函数进行友元声明// 友元函数的独立声明 上面下面都可以 int f_func1(); class T { // 仅仅表示友元声明 表示友元关系定义了访问权限而已 并不是通常意义的函数声明 friend int f_func1(); friend int f_func2(); }; // 友元函数的独立声明 上面下面都可以 int f_func2();