BASIC GRAMMAR
输入字输出
char ch; char str[15]; char ch; char str[15];
sacnf("%c",&ch); scanf("%s",str); ch=getchar(); gets(str);
cin.get(字符数组名,接受字符数目)
cin.getline(字符数组名,接受字符数目)
puts()在输出字符串时会将’\0’自动转换成’\n’进行输出,也就是说,puts方法输出完字符串后会自动换行
string s;
getline(cin, s);
cin>>与getline的工作方式,流提取运算符根据它后面的变量类型读取数据,从非空白符号开始,遇到Enter、Space、Tab键时结束。getline函数从istream中读取一行数据,当遇到“\n”时结束返回。
sscanf and sprintf
sscanf(str, "%d", &n) 将字符串str中的内容以%d的格式输入到n;
sprintf(str, "%d", n) 将n以%d的格式输入到字符串str中
this指针
当你进入一间房子之后,你可以看见桌子、椅子、地板,但是房子的全貌你看不到了,对于一个实例来说,可以看到成员函数、成员变量,但是看不到实例本身,this指针就是这样一个指针,它时刻指向这个实例本身
- this指针本质上是一个函数参数,只能在成员函数(类成员函数)中使用,全局函数、静态函数都不能使用
- this在成员函数开始执行前构造,成员的执行结束后清除
struct 与tpyedef struct
在C中定义一个结构体类型要用typedef:
typedef struct Student
{
int a;
}Stu;
于是在声明变量的时候就可:Stu stu1;(如果没有typedef就必须用struct Student stu1;来声明)
这里的Stu实际上就是struct Student的别名。Stu==struct Student
另外这里也可以不写Student(于是也不能struct Student stu1;了,必须是Stu stu1;)
typedef struct
{
int a;
}Stu;
但在c++里很简单,直接
struct Student
{
int a;
};
于是就定义了结构体类型Student,声明变量时直接Student stu2;
size_t
size_t 是为了方便系统之间的移植而定义的
在32位系统上 定义为 unsigned int
在64位系统上 定义为 unsigned long
malloc与 动态内存分配new
//一维
char* pvalue = NULL; // 初始化为 null 的指针
pvalue = new char[20]; // 为变量请求内存
delete [] pvalue;
二维
int **array // 假定数组第一维长度为 m, 第二维长度为 n
array = new int *[m];
for( int i=0; i<m; i++ ) { array[i] = new int [n] ; }
//释放 两种方式
for( int i=0; i<m; i++ ) { delete [] arrar[i]; } //1
delete [] array; //2
调用函数时,主调的函数所拥有的局部变量等信息需要存储在特定的内存区域,这个区域被称作栈内存,使用new或者malloc进行分配的内存区域被称为堆内存
malloc/free 和 new/delete的区别
①malloc/free是标准库函数,new/delete是c++运算符;
②New操作符从自由存储区(free store)上为对象动态分配内存空间,而malloc函数从堆上动态分配内存
③内存分配失败是返回的值不一样,malloc返回NULL,new抛出异常
④new/delete会调用对象的构造函数/析构函数,而malloc则不会
return的用法
- return;
- return expression;
不带返回值的return语句只能用于返回类型为void的函数,return语句是为了引起函数的强制结束,类似于循环结构的break语句
任何返回类型不是void的函数都必须返回一个值,而且这个返回值的类型必须和函数的返回类型相同,或者能隐式转化为函数的返回类型
指针和引用
为什么使用引用:
可以修改调用函数中的数据对象
传递引用而不是整个数据对象,提高程序的运行速度
引用是已定义变量的别名。引用的主要用途是函数的形参,函数将使用原始数据而不是拷贝
- 引用不能为空,必须在声明引用时将其初始化
- 使用引用前不需要测试它的合法性,指针需要测试,防止其为空
- 指针可以被重新赋值以指向不同的对象,而引用总是指向在初始化时被指定的对象,以后不能改变,但是指向的内容可以改变
- 如果总是指向一个对象并且一旦指向一个对象就不会改变指向,则应该指向引用
指针数组和数组指针
int (*ptr) [] 这是数组指针 指向数组的指针,代表他是指针,指向整个数组
int *ptr[] int *(ptr[]) 这是指针数组 指针数组是说一个数组里面装着指针
函数指针
Float (**def)[10] def是一个二级指针,指向一个一维数组的指针
Double *(*gh)[10] gh是一个指针,它指向一个一维数组,数组元素都是double*
Double(*f[10])() f是一个数组,f有10个元素,元素都是函数的指针
Int *((*b)[10]) b是一个指针,它指向一个一维数组,数组元素都是int*
Long (*fun) (int) 函数指针
Int (*(*f)(int,int)) (int) f是一个函数的指针,指向的函数有两个int参数,并且返回一 个函数指针的函数,返回的函数指针指向一个int参数且返回int的函数
迷途指针(悬浮指针、失控指针)和空指针
迷途指针是当一个指针进行delete操作后(这样会释放它所指向的内存),但指针本身依然存在并没有把它设置为空产生的
虚指针
虚指针或者虚函数指针是一个虚函数的实现细节,带有虚函数的类中的每一个对象都有一个虚指针指向该类的虚函数表
sturct和class的区别
class中变量默认是private,struct中变量默认是public,struct可以有构造函数、析构函数,之间也可以继承,c++中class和struct是一样的
点(.)和箭头(->)操作符
Essential C++ P47中当函数参数列表使用&时使用的是 . 操作符,当使用 * 时使用的是->操作符
c++中当定义类对象是指针对象时候,就需要用到 “->” 指向类中的成员;当定义一般对象时候时就需要用到 “.” 指向类中的成员
箭头(->):左边必须为指针;
点号(.):左边必须为实体。
const
使用const可以避免无意中修改数据
使用const可以处理const和非const实参,否者不能处理const数据
使用const引用是函数能够正确的生成并使用临时变量
const int * a = &b
int const *a = &b;
const 在星号的左边,则const是用来修饰指针所指向的变量,const和数据类型定义符可以互换
int * const a = &b
const在星号的右边,则是修饰指针本身,指针是常量类型
const int * const a = &b
两边都有const 则指针所指向的变量和指针本身都是常量
- const常量赋值时,必须同时初始化
OBJECT-ORIENTED PROGRAMMING
面向对象设计三原则:封装、继承、多态
封装:隐藏实现细节使得代码模块化-------------代码重用
继承:扩张已存在的代码块(类) -------------代码重用
多态:接口重用
C++中会引入额外开销的有:虚基类,虚函数,RTTI,异常,对象的构造析构函数
经常需要操作的内存有:
- 栈区(stact):由编译器自动分配和释放,存放函数的参数值、局部变量
- 堆区(heap):一般由程序员释放,若不释放,程序结束时由操作系统回收,与数据结构中的堆不是一个概念
- 全局区(静态区)(static):全局变量和静态变量存储在一起,结束后系统自动回收
- 文字常量区:常量字符串就放在这里,程序结束后由系统释放
- 程序代码区:存放函数体的二进制代码
实例化
在面向对象的编程中,通常把用类创建对象的过程称为实例化,创建对象的过程
继承
继承允许我们依据另一个类来定义一个类
派生类不能直接访问基类的私有成员,必须通过基类方法进行访问,具体地说,派生类构造函数必须使用基类构造函数
多态
多态: 调用成员函数时,会根据调用函数的对象的类型来执行不同的函数。
简单的概括为“一个接口,多种方法“,在程序运行的过程中才决定调用的函数,函数地址是在运行期间绑定的(晚绑定)。
多态有两种表现形式:重载和覆盖
①重载函数:
参数列表不同(可能是参数类型不同,可能是参数个数不同),编译器将调用者提供的实际参数拿来和每个参数重载函数的参数对比,找出最合适的。这就是每个重载函数的参数列表必须和其他重载函数不同的原因,编译器无法通过函数返回类型来区分具有相同名称的函数。
重载不是一种面向对象的编程,而只是一种语法规则
②覆盖
虚函数总是在派生类中被改写,这种改写被称为“override”(覆盖),就是派生类重写基类的虚函数。覆盖时函数名和参数要和父类中完全一样
(简单的说就是:继承一个类,也就有了父类了全部方法,如果你感到哪个方法不爽,功能要变,那就把那个函数在子类中重新实现一遍。)
protected关键字
private和protected之间的区别只有在基类派生的类中才会表现出来。派生类的成员可以直接访问基类的保护成员,但不能直接访问基类的私有成员。对外部世界来说,保护成员的行为与私有成员相似;但对于派生类来说,保护成员的行为与公有成员相似。
extern
声明函数或变量的作用范围的关键字,其声明的函数和变量可以在本编译单元或其他编译单元中使用
inline(内联)函数
要求编译器在每个函数调用点上将函数的内容展开,编译器可将该函数的调用操作改为以一份函数代码为副本代替。
最适合声明为inline函数:体积小,常被调用,所从事的计算并不复杂
有些在class内声明但是没有定义的函数,在class外定义时需要使用inline关键字关联
class定义及其inline member function 通常都会被放在与class同名的头文件中
模板函数
如果要定义3个不同的display_message()函数,分别处理int、double、string,写三个函数太费时间,而且这三个函数非常类似。如果只定义一份函数就好了,这就引出的模板函数。
Template<typename elemType>
友元函数
类的友元函数是定义在类外部的普通函数,但它需要在类体内进行说明:加关键只friend,有权访问类的所有私有(private)成员和保护(protected)成员。尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数。
其作用是提高程序的运行效率
公有继承,私有继承,保护继承
| 私有成员 | 公有成员 | 保护成员 |
公有继承 | 私有,派生类不可见 派生类对象不可见 | 派生类可见,还是公有成员 派生类对象可见 | 派生类可见,还是保护成员 派生类对象不可见 |
私有继承 | 私有,派生类不可见 派生类对象不可见 | 派生类可见,成为派生类的私有成员 派生类对象不可见 | 派生类可见,成为派生类的私有成员 派生类对象不可见 |
保护继承 | 私有,派生类不可见 派生类对象不可见 | 派生类可见,成为派生类的保护成员 派生类对象不可见 | 派生类可见,成为派生类的保护成员 派生类对象不可见 |
类继承时需要制定继承方式,C++默认是私有继承,如果不指定则都为私有继承
虚函数
静态成员函数无法被声明成虚拟函数。
将虚函数赋值为0,便是一个纯虚函数。
定义一个函数为虚函数,不代表函数为不被实现的函数。
定义他为虚函数是为了允许用基类的指针来调用子类的这个函数。
定义一个函数为纯虚函数,才代表函数没有被实现。
定义纯虚函数是为了实现一个接口,起到一个规范的作用,规范继承这个类的程序员必须实现这个函数
虚继承
虚拟继承是多重继承中特有的概念,虚拟继承是为解决多重继承而出现的
A-------B A-------C B继承A,C继承A
B,C------D D继承B,C,这样的话在D类中会出现两次A,为了节省内存空间,将B,C对A的继承定义为虚拟继承,A就成了虚拟基类
异常处理
throw 抛出异常
try 需要注意这些代码引发的异常
catch 异常被引发时,跳到这个位置执行
多线程
基于进程的多任务处理是程序的并发执行。
基于线程的多任务处理是同一程序的片段的并发执行
web编程
公共网关接口(CGI),是一套标准,定义了信息是如何在 Web 服务器和客户端脚本之间进行交换的
用于外部网关程序与信息服务器(如 HTTP 服务器)对接的接口标准