Chris Li

Digital design, Lisper,Emacs.

C

Table of Contents

概念

  1. 强静态类型 C++是静态类型语言,编译时进行语法检查,特点是变 量使用前必声明,函数参数类型检查。
  2. 容器 vector,可以用于不同的数据类型,但是一个容器中的所有对象必须是 同一种类型
  3. 类模板 类定义可以及用于不同的数据类型
  4. vector对象动态增长 vector不在一开始分配内存,先定义一个空的 vector,在后期动态增加反而效率更高。
  5. size_type 有具体类型,string实际返加为string::size_type,而vector中 为vector<T>::size_type
  6. 缓冲区溢出 有可能是数组或其它类似数据类型地址越界
  7. 未初始化的指针 容易导致错误
  8. 复合数据类型的赋值问题 复合数类型的赋值总是比较严格。
  9. 自由存储区(free store)/堆(heap) 内存中用于存放动态对象的空间
  10. 临时对象 求解表达式创建的没有名字的对象,如函数返回值,实参初始化 形参
  11. 函数名和变量名及作用域 函数名和变量名并没有本质上的不同,在作用域 中相同考虑,但一般函数声明在头文件中,具有全局作用域。
  12. C++中类型查找发生在类型检查前

C++调试工具

NDEBUG

assert

try/throw

ifdefine

第一章

  • 读入未知数目的输入
while (std:cin >> value)//以是否输入“文件结束符”为判断标准
sum +=value;
  • 表达式/语句
  • 标准库头文件与非标准库头文件写法的区别
  • 对象
  • 成员函数/方法
  • 标准输入输出可以对类进行写读
  • 怎么调用成员函数/点操作符
  • 调用操作符

第一部分 基本语言

变量和基本类型

基本,类,复合

基本内置类型

char,wchar_t,int,bool,short,long,float,double,long,double 整形&char有unsigned/signed,默认为signed signed(无论是否超范围)赋给unsigned时,补码来模。

字面值常量

  • 整形常量
    • 进制(0,0x)
    • U,L
  • 浮点常量
    • F,L,E
  • bool常量
    • ture/false,非零值
  • 字符常量
    • ''
    • L
  • 非打印字符
    • \n,\t,\\,\r,\',\",\?
    • \ASCII
  • 字符串字面值
    • “”
    • L
    • 未尾空字符
    • 多行字符串与连接
      • 宽字符串与一般字符串不可连接
    • 语句中的\

变量

  • 自动初始化规则
    • 函数体外/函数体内
  • 声明与定义
    • extern
    • 变量默认为extern变量,全局变量
  • 作用域
    • 全局作用域/函数外
    • 局部作用域/函数内
    • 语句作用域/语句中
    • 作用域的嵌套规则
    • 类作用域
    • 命名空间作用域

const限定符

将变量转化为字面值 魔数 const对象默认为非extern,即局部变量。

引用

  • 复合类型
  • 必须显示初始化,指向某个对象,之后始终指向该对象
  • 在名字前加&
  • 指向同一个对象
  • const引用
    • 引用中const属性一致
    • 一般引用必需绑定到同类型对象,且不能是字面值右值
    • const引用可以绑定到相关类型对象,且可以是字面值右值
    • 临时变量
double dval=3.14;
const int &ri=dval;

turn to

int temp=dval;
const int &ri=temp; 

typedef

typedef double double_2;

枚举

  • const
  • 枚举初始化,只能被同名/类型枚举成员初始化

类类型

  • 成员
    • 成员函数
    • 数据成员
  • 访问标号
    • class 第一个为private
    • struct 第一个为public

编写自已的头文件

  • 声明
  • const定义
  • 头文件保护符
  • 函数声明/默认实参
#ifndef SALE
#define SALE
...  ...定义头文件 .
#endif  

标准库类型

配套类型-迭代器

命名空间using声明

using namespace::std;//declear all std name
using std::cin; //分别声明                 
using std::cout;.
using std::endl;

标准库string类型

  • string和字符串字面值不一样
  • string的初始化方法
string s1; 默认构造函数
string s2(s1); 将s2初始化为s1
string s3("value"); 用字符串字面值初始化s3,不含\n
string s4(5,'c'); s4初始化"ccccc"
  • string的读写
    • 读入末知数目的string对象,输出流中的单词
string word;
while (cin>>word)
cout<< word<<endl;
  • 用getline读取文本,输出整行
string word;
while (getline(cin,word))
cout<<word<<endl;
  • getline与cin的区别
    • getline不忽略开头的换行符
    • getline接受空格,按行输出
  • string对象的操作
s.empty() 如果s为空串,则返回trun
s.size() 返回字符的个数
s[n] 返加s位置为n的字符
s1+s2 将s1和s2连接
s1=s2 替换为s2
s1==s2 比较,相同为true
!=,<,<=,>,>=  
  • string::size_type类型
  • string大小的比较规则
  • string连接相+规则
  • s[n]获取字符,可对string进行任意操作,n可以是整形,最好是size_type类 型
  • cctype/string中字符处理

标准库vector类型

  • 声明
vector<int> ivec;
vector<sale_item> sale_vec;
  • 定义
vector<T> v1;
vector<T> v2(v1);//v1,v2的T为同一类型
vector<T> v3(n,i);
vector<T> v4(n);//默认构造函数/默认初始化 对n 个元素进行初始化
  • vector对象的操作,类似于string
v.empry() 如果v为空,则返回true
v.size 返回v中元素的个数
v.push_back(t) 在v 的末尾 增加一个值为t 的元素
v[n] 返回v中位置为n的元素
v1=v2 赋值
v1==v2 v1和v2是否相同
!=,<,<=,>>= 同string
  • 下标操作不能添加元素,只能改变元素

迭代器简介

  • 只有少数容器定义了下标操作,而所有容器都支持迭代器
  • 定义,与size_type一样iterator对应具体容器类型,对应vector<int>,而不 是vector。
vector<int>::iterator iter;
  • begin和end操作
vector<int>iterator iter=ivec.begin();ivec有第一个
vector<int>iterator iter=ivec.end();ivec末端元素的下一个,哨兵

如果ivec为空,则begin和end指向同一个地方

  • 自增和解引用
    • 解引用 *,如*iter=0
    • 自增++iter
  • 迭代器的!=,==
  • const_iterator和const的iterator不一样
vector<int>::const_iterator iter;
const vector<int>::iterator iter;
  • 迭代器的size_type和difference_type(signed)
  • 迭代器与容器大小相关,改变容器大小,迭代器失效

标准库bitset类型

  • 定义和初始化
bitset<int/const int> bitvec;
bitset<n> b; n位0|
bitset<n> b(u); u的副本,u为unsigned long
bitset<n> b(s); string对象中含有位串的部分,左高右低 ,s应为0,1的组合
bitset<n> b(s,pos,n); 从位置pos开始的n位,省略n则取到未尾
  • bitset对象的操作
    • 支持cout
    • 支持位操作符
    • size_t类型,unsigned,在cstddef中定义
    • 支持下标操作
    • 可以与unsigned long之间转化

数组和指针

数组和指针速度比标准库类型快,但不如标准库好用,不能动态改变 现代C++不看好数组,也不看好指针,更不看好C风格字符串

  • 复合数据类型
  • 数组元素可是类或复合数据类型
  • 维数为大于或等于1的常量/常量表达式
  • 数组初始化若没显示初始化,则初始化规则与变量类似
int ia[3]={0,1,2,};//
  • 显示初始化的数组维数可以不指定
  • 指定大小后元素值可以小,不能大
  • 使用字符串字面值初始化字符数组的维数问题
  • 数组不可以整个复制,赋值
  • 数组下标的类型是size_t

指针

  • 复合数据类型
  • 指针类型与对象相对应
  • 数组的迭代器,*,++等操作与迭代器类似
  • 指针与迭代器的区别
    • 指针可以指向任意对象,迭代器只能是容器
  • &取地址,指针相当于地址
  • 两种声明格式
  • 有效指针的三种状态
    • 特定对象的地址
    • 指向某个对象后的另一个对象
    • 0
  • std::NULL
  • void*指针,仅仅只能做为地址值,不能操纵对象
    • 指针比较
    • 形参或返回值
    • void*之间赋值
  • 通过指针解引用改变对象的值,不会改变指针的值,也不会改变对象名
  • 指针和引用的区别
  • 指针本身也是一个对象,所有指针的类型应该相同,只是其所指向的对象类型 不同
  • 指针对数组的操作
int ia[]={0,2,4,6,8};
int *ip=ia;//ia=&ia[0];
int* ip=&ia[4];
int* ip2=ip+2;
  • ptrdiff_t类型,在cstddef中定义
  • 指针 加0 合法
  • int,size_t,数组名这间可以进行算术操作
    • 其实size_t的单位是字节,数组名是指针。此时如果与int进行算术操作, 则int的单位是数组元素的大小。
  • 允许指针计算end位置,但不能解引用操作
  • 指针的下标操作,下标不是size_t类型
  • 指向const对象的指针/const指针
const double *cptr;
double *const cptr;
  • 要保存const对象的地址,使用const void*,而不是void*
  • 非const对象的地址可以赋给指向const对象的指针,此时若要改变非const对 象的值,不能通过指针解引用的方式。所以指向const对象的指针所指的对象 并不是不可以改变的,只是不能通过指针的方式改变。
  • 指向const对象的const指针
  • 指针与typedef
string s;
typedef string * pstring;
const pstring cstr1=&s;
pstring const cstr2=&s;
string * const cstr3=&s;

cstr1,cstr2,cstr3都是指向string的const指针

C风格字符串

  • C风格字符串是以\0结束的const char数级,如字符串字面值
  • \0的bool值为false
  • 字符串字面值是const char 类型的数组
char ca1[]={'c','g','e','\0'};
char ca2[]="cge";
const char *pa="cge";
char *pb=ca1;

以上都是C风格的字符串的”定义“

  • cstring标准库
strlen(s) 返回s的长度,不包括\0 ,在使用strncat,strncpy时应考虑实际大
strcmp(s1,s2) 比较两字符串,返回bool值
strcat(s1,s2) s1+s2连接两字符串
strcpy(s1,s2) s1=s2,返回s1,大小会改变
strncat(s1,s2,n) s1+s2的前n个字符,返回s1
strncpy(s1,s2,n) s1=s2的前n个字符,返回s1
  • 直接用关系操作符操作C风格字符串,实际上是比较两者的指针地址
if(cp1<cp2)
  • strncpy,strnca比strcat,strcpy更安全

动态数组

int *pia=new int[10];//无需数组名,大小可以是变量/表达式
  • 动态数组由程序员控制new/delete,
  • 取消动态数组delete [] pia
  • 动态数组的初始化规则
    • 内置类型
int *ipa=new int[10]();//加()使得编译器想办法初始化,不能提供具体值
  • const对象的动态数组必须初始化为默认值,所以这种数组用处不大
  • 动态数组支持0大小,返回指针不能进行解引用操作,允许比较操作

新旧代码兼容

  • C风格字符串与字符串字面值等价
  • 不能用string初始化C风格字符串,可以用c_str的成员函数,返回值为 const char*类型
  • 使用数组初始化vector对象
const size_t arr_size=6;
int int_arr[arr_size]={0,1,2,3,4,5,};
vector<int> ivec(int_arr,int_arr+arr_size);用地址初始化vector.
vector<int> ivec2(int_arr+1,int_arr+4);

多维数组

数组的数组

  • n维数组对应n个下标
  • 初始化
int ia[3][4]={{0,1,2,3},{4,5,6,7},{1,2,3,4}};
  • 多维数组的默认初始化规则
    • 一般情况与数组初始化规则类似
    • 花括号
  • 多维数下标引用,一个下标,两个下标
  • 数组名实制是指针/多维数组的指针
int (*ip)[4]=ia;//注意与 int *ip[4]=ia;的区别,
  • 多维数组的指针,解引用产生小数组的指针,注意必须要有解引用,虽然指针 的值与解引用的值相同
ip=&ia[2];//从多维数组的第2个小数组开始的指针
  • 用typedef简化多维数组的指针的定义
typedef int int_array[4];
int_array *ip=ia;

表达式

  • 由操作数和操作符组成产生结果
  • 左值/右值
  • bitset中的reset较方便
  • IO操作符为左结合性
  • 赋值操作符为右结合性,而且优先级较低
  • 箭头操作符
sale_item *sp=&item1;

因为容易忘记括号箭头操作符将(*sp).same_isbn(item2)简化为 sp->same_isbn(item2);

  • sizeof返回size_t类型(以字节为单位),表示对象或类型的长度,不是实际 存储空间大小
  • 逗号操作符
    • 常用于for循环,结果为最右边表达示的值
  • 圆括号凌驾于优先级之上
  • 除优先级之外的求值顺序
&& || ?:   ,有影响时先求右操作数
  • 动态创建对象,不提供对象名,仅通过指针访问
  • 所有零指针都可以被delete
  • 悬垂指针
  • const动态对象必须在创建时初始化
  • 隐式类型转化
    • 混合类型表达式中
    • 条件表达式中,转化为bool
    • 赋值语句中
  • 算术转换
    • 整型提升,char,signed char,unsigned char,short,unsigned short->int->unsigned int
    • 一 般先转化为有signed,表示不了则转化unsigned
    • 指针可以转化为bool类型
    • 枚举类型可转化算术类型
  • 显示转换/强制类型转换cast
    • static_cast,dynamic_cast,const_cast,reinterpret_cast
    • cast-name<type>(expression);
    • const_cast去掉表达式的const特性
    • static_cast,完成所有的隐式转换
    • reininterpret_cast通常为操作数的位模式提供较低层次的重新解释
  • 旧式强制类型转换,只在老的编译器中建议使用
    • char *pc=(char *) ip;

语句

  • for循环的初始化语句同时定义多个变量的情况
  • 空语句
  • 复合语句/语句块{}

异常处理

  • throw表达式/try块
    • try块内的变量为局部变量/引入局部作用域,catch也是
    • 使用预处理变量NDEBUG的宏定义来调试程序
    • 使用assert(expr)来对C++进行断言,表达式错误将终止程序,在宏定义 NDEBUG情况下无效,

函数

函数体是一个局部作用域

  • 定义函数的好处
    • 阅读理解方便
    • 修改代价小,只需找出函数修改即可
    • 确保行为统一
    • 代码可以重用
  • 调用操作符
  • 返回类型,必须指定
Date &calendar(const char*);
void process();
  • 函数形参表的圆括号和函数体的花括号间可以加任意空格或换行符

参数传递

  • 形参表可为空
  • 参数传递
    • 非引用形参/副本
      • 指针形参
      • const形参
    • 引用形参
      • 使用引用形参返回除返回值之外的信息,引用形参会改变外部变量
      • 利用const引用避免利复制,引用避免复制,const可以使得形参可以传递的 实参种类更多(只要相关类型)
      • 指向指针的引用
void ptrswap(int *&v1,int *&v2){}
  • vector和其它容器类型的形参
    • 函数中vector和其他容器类型的形参应做为引用形参,不然函数复制开销太 大
  • 数组形参,由于数组和指针本质上是一个概念,所以和容器类型不同,数组在 以非引用传递时,不会复制数组,而是以复制数组指针的方式。
    • 定义
void printValues (int *) {}
void printValues (int []){}
void printValues (int[10]){}//虽然指定了大小,但编译器不会检查数组大小,相当于没有指定
  • 若不想修改数组,则应将形参指针定义为const type *,即指向const对象的 指针
  • 通过引用传递数组,数组将不会转化指针,也不会复制数组,但此时会检查 数组大小
  • 看数据类型定义时,因从右往左看,下标的优先级比较高,所以数组的引用, 应写为如下的形式
int (&arr)[10],首先是引用,然后是数组的引用 
int &arr[10],首先是数组,引用的数组
  • 多维数组的传递
void printValues(int(*matrix)[10],int rowSize);//与一维数不同,多维数组必需指定除一维外的其它维数
  • 使用数组传递是应注意,数组第一维的大小问题,不能越界,目前有三种方法
    • 数组本身存放一个结束符,如C 风格字符串
    • 传递数组的第一个元素和最后一个元素位置
    • 显示传递数组大小
  • 可变形参函数
    • 暂停实参类型检查
    • 只要提供形参,就会按顺序对对应实参进行类型检查
    • 第一种形式更常用
void foo(parm_list,...);
void foo(...);

返回值

  • 返回值的两种形式
  • 函数返回值为临时对象,不能为左值,引用返回值例外
  • void与return
    • return;
    • return void function;
  • return可以省略,但不省略则类型必需对应,正常情况下非void函数都要有 return语指明返回值,main函数例外,编译器会隐式插入返回0的语句。
  • 非void函数不能有不带返回值的函数
  • cstdlib与main函数返回值
  • 返回引用/不能返回局部对象的引用
  • 不能返回指向局部对象的指针
  • 引用返回左值,可以及给函数返回值赋值
  • 函数引用返回值可加const属性,此时不可以给函数返回值赋值
  • 函数递归/注意结束条件,死循环

函数声明

  • 函数声明,函数声明和定义分离
  • 函数原型
    • 返回类型,函数名,形参表
    • 函数声明中的形参表和函数定义形参表不同

默认实参

  • 定义默认实参的提供规则
  • 没提供默认实参的函数调用不能省略实参
  • 调用时参数替换规则
  • 默认实参可以是任何适当的表达式
  • 默认实参出现的位置及约束

局部对象

自动对象 函数中的局部变量,形参

  • 静态局部对象static,位于函数的局部作用域中,但生命期却跨越了多次函数调用

内联函数

  • 减少函数调用开销,使函数开销相当于表达式。
  • 定义在头文件中,不能只有声明

类的成员函数

成员函数可以在类外定义,函数原型必需在类中

  • 类中定义的函数与类外定义的函数的区别
  • 成员函数含有额外的、隐含的形参
  • 隐含的形参的指针叫做this指针,this指针为const指针
  • const 成员函数/常量成员函数,使this指针指向的对象为const,从而达到 不改变对象的目的
  • const 对象只能调用const成员函数,反之不成立。
  • 任何没有前缀的数据成员,都使用了this指针
  • 成员函数可以访问private成员
  • 类外定义成员函数使用作用域操作符
  • 构造函数
    • 构造函数是特殊的成员函数,用来初始化数据成员。
    • 特点
      • 与类名同名
      • 没有返加值类型,没有返回值
      • 有初始式
      • 多个构造函数间以形参区分
    • 没有形参或提供默认实参的构造函数称为默认构造函数
    • 合成的默认构造函数
      • 有可能不初始化内置类型成员
      • 类中的成员函数声明和定义都应被include

重载函数,同作用域中函数名字相同形参表不同

  • main函数不能被重载
  • 作用域优先于重载,只在一个作用域中重载
  • 重载确定三步骤
    • 确定候选函数
    • 选择可行函数
      • 函数形参个数相同,注意默认实参因素
      • 形参与实参类型匹配
  • 匹配等级
    • 精确匹配
    • 类型提升匹配
    • 标准转换匹配
    • 类类型转换
  • 对整形的实参值,int版本优于short版本
  • char到int优于char到double,其它类型转换类似
  • 通过类型提升实现的转化优于其它标准转化
  • char到unsigned char不比从char到double高
  • 整形不能到enum,但enum可以到整形
  • 可根据形参是不为const 引用重载函数
  • 非const对象到非const形参是精确匹配,非const对象的指针到非const指针为 精确匹配,不能基于指针本身是否为const实现重载。

指向函数的指针

bool (*pd)(int a,int b);
  • 用typedef简化指针定义
  • 函数名相当于指向函数的指针
  • 函数指针赋值规则
    • 同类型指针之间可以赋值
    • 可以赋0
  • 通过指针调用函数,注意第二种形式的括号
pf("hi","bye");//pf为指向函数的指针
(*pf)("hi","bye");//这各形式也可以
  • 指向函数的指针可以做形参,有两种形式
void usebig(int a,bool(const string));
void usebig(int a,bool (*)(const string));
  • 指向函数的指针可以做为返回值
int (*ff(int))(int*,int);//从内向外理解
  • 指向函数的指针做形参和通指针调用函数有两种形式,而定义只有一种形式, 注意区分函数类型和指向函数指针类型的区别
  • 函数类型不能用来调用函数
  • 指向函数的指针可指向重载函数,重载必须精确匹配
void ff(vector<double>);
void ff(unsigned int);
void (*pf)(unsigned int)=&ff;//重载选择void ff(unsigned int);

标准IO库

第二部分 容器与算法

接口、算法、类型

  • 容器只定义了少量操作,大量额外操作由算法库提供
  • 容器类型操作/算法层次
    • 适合所有容器的操作
    • 只适用于顺序容器或者关联容器
    • 只适用于顺序容器中的某些容器
  • 大部分程序中,容器定义时使用默认构造函数能达到最佳性能

顺序容器

顺序容器的定义

  • 容器元素的初始化
    • 标准库的三种容器类型
    • 标准库的三种容器适配器adaptor
    • 容器构造函数
    C<T> c; 创建空容器,对所有容器有效
    C c(c2); 创建c2的副本,要求容器类型和元素类型必需相同,对所有容器有效
    C c(b,e); 用迭代器来创建c,要求容器元素为相关类型,容器类型不要求,对所有容器有效
    C c(n,t); 用n个t创建c,t值与c容器类型相关,只适用于顺序容器
    C c(n); 创建大小为n的容器,容器中的元素默认初始化,只适用于顺序容器
    • 计算数组大小
    int a[]={1,2,3,4};
    size_t words_size=sizeof(words)/sizeof(int);
    
  • 容器内元素的类型约束

迭代器和迭代器范围

  • 迭代器范围
  • 使迭代器失效的容器操作

顺序容器的操作

  • 容器定义的类型别名
  • begin和end成员
  • 在顺序容器中添加元素
  • 关系操作符
  • 容器大小的操作
  • 访问元素
  • 删除元素
  • 赋值与swap

vector容器的自增长

容器的选用

再谈string类型

  • 构造string对象的其他方法
  • 修改string对象的其他方法
  • 只适用于string类型的操作
  • string类型 的查找操作
  • string对象的比较

容器适配器

  • 栈适配器
  • 队列和优先级队列

关联容器

引言:pair类型

关联容器

map类型

  • map对象的定义
  • map定义的类型
  • 给map添加元素
  • map::insert的使用
  • 查找并读取map中的元素
  • 从map对象中删除元素
  • map对象的迭代遍历
  • “单词转换”map对象

set类型

  • set容器的定义和使用
  • 创建“单词排除”集

multimap和multiset类型

  • 元素的添加和删除
  • 在multimap和multiset中查找元素

容器的综合应用:文本查询程序

  • 查询程序的设计
  • TextQuery类
  • TextQuery类的使用
  • 编写成员函数

泛型算法

概述

初窥算法

  • 只读算法
  • 写容器元素的算法
  • 对容器元素重新排序的算法

再谈迭代器

  • 插入迭代器
  • iostream迭代器
  • 反向迭代器
  • const迭代器
  • 五种迭代器

泛型算法的结构

  • 算法的形参模式
  • 算法的命名规范

容器特有的算法

第三部分 类和数据抽象/抽象数据类型

12章 类

  • 类的定义是一个作用域
  • 类的数据成员不能在类体中进行初始化,const static成员除外,const static在类体中定义时就可以进行初始化,也可以在类体外进行初始化
  • 类中定义的成员函数模认为inline
  • const成员函数不能改变对象的数据成员
  • 类的好处
    • 避免类内部出现无意的,用户级错误
    • 随着时间的推移来完善类的实现,而无须改变用户级代码
  • 类定义中可以使用typedef,别名只能在类定义中使用,不能在用户代码中使 用
  • 成员函数可被重载,重载范围仅限该类中的成员函数。
  • 成员函数的inline声明,仅可在类定义中声明,也可以在类外声明,而不像 const声明
  • 声明类,声明之后,该类只能用于定义和声明,不能使用该类定义的对象,在 这个类被定义之后才能使用
  • 类的定义中不能有自身类型的数据成员,但可以有指向自身类型的指针或引用
  • 类定义的花括号和分号之间是用来定义对象的
  • 数据成员的定义可以像变量的定义一样,多个一起写
  • this指针的使用
    • 多次成员函数调用,写成一个表达式
    • 返加对自身类对象的引用,要用return *this
    • 返回对自身的类对象的引用的时候,要考虑是否是const成员函数,const成 员函数返加const this指针,该种类型指针在调用其它非const成员函数会 存大问题
  • const对象只能调用const成员函数,非const对象无所谓,但非const成员函数 为更好的匹配
  • mutable/可变数据成员,const成员函数也能改写
  • 类的定义是一个单独的作用域,包括类体外定义的函数的形参表与函数体,返 加值不包括
  • 成员访问操作符. ->,对应于 类 类指针
  • 名字查找
    • 一般顺序:块/类中,块/类前
    • 类中成员函数:函数中,类中,类前
      • 显式调用外部作用域类中名字screen::height
      • 显式调用全局作用域中的各字 ::height
  • 构造函数不能为const
  • 构造函数两个阶段,初始化,计算(赋值)。两种情况必须出现在初始化阶段
    • const对象
    • 引用
  • 构造函数中的初始化顺序
  • 初始化式可以是任意表达式
  • 构造函数中可以使用默认实参
  • 默认构造函数/合成默认构造函数
  • 什么情况下会生成默认构造函数
  • 通常类应提供一个默认构造函数,不然该类的使用会受到限制 :
    • 必须显示传递参数来初始化该类
    • 不能用作动态分配数组的元素类型
    • 在静态分配数组中也必须为每个元素提供一个显式的初始化式
    • 在容器定义中,不能只指定容器大小而没有提供构造函数
  • 隐式类类型转换
    • 容易形成临时对象
    • explicit/显示构造函数,抑制隐式类类型转换,一般单形参构造函数需要 抑制隐式类类型转换
    • 显示使用构造函数
  • public成员可以显示初始化/直接初始化
  • 友元/private成员访问权限的控制,授予指定函数或类类型(不是一个具体 对象)
  • 友元是类的话,则该类不必事先声明。
  • 友元是函数成员的话,则该函数必需预先声明(不是定义)。
  • 友元只对应重载函数中的一个。
  • static 类成员/静态成员不是类对象的组成部分。
  • static成员的优点
    • 处在类的作用域中,维持封装特性,名字与全局对象不冲突
    • 便于阅读,相半性明确
  • static成员处在类中,是类中的一个特殊成员
  • static成员函数在外部定义时,不重复static关键字,static关键字只用于类 体内部
  • static函数没有this指针
  • static成员不是类对象的组成部分,所以可以这样写
class Bar {
public:
private:
      static Bar mem1;
      Bar *mem2;
      Bar mem3;

例2:用作默认实参

class screen {
public:
     screen & clear(char=bkground);
private:
     static const char bkground ='#';
};

复制控制类

新类型的---复制、赋值、撤消

重载操作符与转换

## C-c C-c "~/org/learn.org" -> "* Tasks" ## C-u C-c C-c like C-c C-c, and immediately visit note at target location ## C-0 C-c C-c "???" -> "* ???" ## C-1 C-c C-c to select file and header location interactively. ## C-2 C-c C-c as child (C-3: as sibling) of the currently clocked item ## To switch templates, use `<f10>'. To abort use `C-c C-k'.

13章 复制控制

  • 复制控制=复制构造函数+析构函数+赋值操作符
  • 复制构造函数,单形参,形参为自身类型的引用(大多为const),与其它构 造函数一样可以显式和隐式调用。
  • 复制函数可用于(=不属于)
    • 根据另一个同类型的对象显式或隐式初始化一个对象
    • 复制一个对象,将它作为实参传给一个函数。
    • 从函数返回时复制一个对象
    • 初始化顺序容器中的元素
    • 根据元素初始化式列表初始化数组元素
  • 直接初始化/复制初始化
  • 复制时需加以控制的数据类型,指针
  • 禁止复制的两种方法
    • 只有成员和友元才能用
    • 成员和友元也不能用
  • 复制构造函数和赋值操作符常在一起使用
  • 三法则,如果需要析构函数那么另外两个肯定也需要

15章 面向对象编程

15.1 面向对象编程概述

基于数据抽象、继承、动态绑定。

  1. 定义相似又不同的类
  2. 编写这些相似类之间的函数

多态性,通过继承而相关联的类型的指针或引用来实现。

  • 派生类 继承 基类,这种关系会构成一个继承层次
  • virtual函数,在继承关系下一种特殊的成员函数,virtual只出现在类中,在 类外定义的virtual函数,不必重复virtual关键字。
  • 虚函数的调用是动态的,即在运行时确定。这种运行时确定的函数调用关系称 为动态绑定。virtual启用动态绑定
  • 静态类型/写好的类型 动态类型/运行中的实际类型

15.2 定义基类和派生类

  • 定义基类
    • 将派生类需要重定义的函数,定义为virtual
    • protect成员允许派生类访问,但不允许普通用户访问,一种特殊成员
  • protected成员
    • 派生只能访问派生类对象的protected成员,而不能访问其基类的对象的 protected成员。
  • 派生类
    • 派生类中的虚函数如果不重新定义,将继承基类中定义的版本。
    • 派生类中的虚函数的声明必须与基类中定义的方式完全匹配
      • 有一个例外:虚函数返回对基类的引用或指针时,则定义在派生类中的虚函 数可以改为返回派生类的引用或指针。
    • 虚函数就一直是虚函数
    • 派生类包含所有基类成员(非static,非private)
    • 基类必须先定义
    • 派生类可以作基类
    • 派生类的声明和普通类的声明一样
  • virtual与其他成员函数
    • 触发绑定的两个条件
      • 虚函数
      • 通过基类的引用或指针进行函数调用
    • 派生类到基类的转换,因为派生类包括基类,所以定义基类引用或指针的形 参,可以传递派生类的实参。
      • 指向基类的指针可以指向派生类
      • 基类的引用可以用派生类来传递,绑定
      • 使用基类指针或引用来传递参数时,不能够知道实际的参数类型,即不知道 绑定的类型。编译都当作是基类。
    • 非虚函数,则会调用基类中的版本
    • 虚函数与::,强制调用
    • 虚函数的默认实参,必免在基类和派生类中都给虚函数指定默认实参
  • 公用、私有和受保护的继承
    • 派生类中自身定义的成员和任意其它类的规则完全一样
    • 派生类所继承的成员,由基类成员的访问标号和派生列表共同控 制。
    • 派生列表定义三种访问级别
      • 公用继承
      • 受保护继承
      • 私有继承
    • 实现继承public/接品继承protect private
    • 定义派生类时---参照"is A"是一种
    • 定义成员时---参照"has A"有一个
    • 派生类中的using声明的使用
  • 友元关系与继承
  • 继承与静态成员

15.3 转换与继承

  • 派生类到基类的转换
  • 基类到派生类的转换

15.4 构造函数和复制控制

  • 基类构造函数和复制控制
  • 派生类构造函数复制控制和继承
  • 虚析构函数
  • 构造函娄和析构函数中的虚函数

15.5 继承情况下的类作用域

  • 名字查找在编译时发生
  • 名字冲突与继承
  • 作用域与成员函数

15.6 纯虚函数

15.7 容器与继承

15.8 句柄类与继承

15.9 再谈文本查询示例

  • 面向对象的解决方案
  • 值型名柄
  • Query_base类
  • Query名柄类
  • 派生类
  • eval函数

gcc stuff

  • glib版本查看
    • ldd –version
    • 具体的库,strings /usr/lib/libstdc++.so.6|grep CXX