C++学习笔记
鉴于C++可看作是C语言的扩展,或者说是面向对象的C语言版本。其语法方面多有类似指出,此笔记也就简要写出C++中与C不同和新增的语法部分。
当然C与C++依然算作是两种语言,此处本人小白,亦不做辩论,只在此方便笔记而已。
1、基本语法
简介
linux下C语言用gcc,C++用g++编译;C++含有对象、类、方法、即使变量等概念。
C++ 的预编译库包含了绝大多数C语言的库,自身格式略有不同
|
|
- 关键字
asm | else | new | this |
---|---|---|---|
auto | enum | operator | throw |
bool | explicit | private | true |
break | export | protected | try |
case | extern | public | typedef |
catch | false | register | typeid |
char | float | reinterpret_cast | typename |
class | for | return | union |
const | friend | short | unsigned |
const_cast | goto | signed | using |
continue | if | sizeof | virtual |
default | inline | static | void |
delete | int | static_cast | volatile |
do | long | struct | wchar_t |
double | mutable | switch | while |
dynamic_cast | namespace | template |
- 三字字符
三字符组 | 替换 | |
---|---|---|
??= | # | |
??/ | \ | |
??’ | ^ | |
??( | [ | |
??) | ] | |
??! | \ | |
??< | { | |
??> | } | |
??- | ~ |
这些都是古老程序,当时为了表示键盘上没有的字符而设计的。
数据类型
bool、char、int、float、double、void、wchar_t(宽字符型),以及signed、unsigned、short、long等修饰符
- typedef定义新名称
1typedef int feet;//那么就可以用feet代替int类型定义变量了- 枚举
1234567enum enum_name{list of names} var-list;//示例enum color{red,green,blue} c;c = blue;//默认情况,第一个值=0,第二个=1,依次+1,也可以直接定义enum shape {rectangle,circle=5,square} sp;//那么此时,square=6,比上一个+1.const声明常量,成员变量自动初始化,char=‘\0’;默认初始值
有符号和无符号的修饰符
123456789101112using namespace std;int main(){short int i;//有符号短整数unsigned short int j;//无符号的j = 50000;//赋值i = j;cout << i << " , " << j;return 0;}//输出结果-15536 , 50000C++限定符
- const 常量修饰符
- volatile 告知编译器,其修饰的变量可能会被未知方式修改
- restrict修饰的指针,是一种唯一访问它所修饰对象的方式
C++存储类
auto、register、static、extern、mutable(用于对象修饰,允许对象成员代替常量,mutable成员可通过const成员修改)
String类
相比char字符类型,增加了许多常用便捷操作
引用
引用不同于指针
- 没有空引用,可以用空指针
- 一旦引用被初始化为一个对象,就不能指向其他对象,指针可以随时变向
- 引用必须创建时初始化,指针可以随时
引用使用
&
符号1234//变量的声明初始化int i = 17;//声明变量i的引用int& r = i;//成为r是初始化为i的整形引用基本输入输出
I/O库
1<iostream>、<iomanip>、<fstream>等- 标准输出cout,输入cin
12345678910using namespace std;int main(){char str[] = "Hello C++";cout << "Value of Str is : " << str << endl;char name[30];cout << "Please input your name";cin >> name;cout << "your name is : "<<name<<endl;//endl -- end line;}- 标准错误流cerr,日志流clog
2、面向对象
对象类
class关键字
12345678910class Box {public ://还有private、protected,friend有点不同double length;double breadth;double height;};//声明类对象Box box1;//然后用.符号访问类成员box1.length继承
C++可以多继承
123456//格式class derived-class : access-specifier base-class//示例class Rectangle : public Shape{...}权限修饰符public、private、protected
| 访问 | public | protected | private |
| —- | —— | ——— | ——- |
| 同一个类 | yes | yes | yes |
| 派生类 | yes | yes | no |
| 外部类 | yes | no | no |派生类可以继承所有基类的方法,例外
- 基类的构造函数、析构函数和拷贝构造函数
- 积累的重载运算符(就是重新定义基本的运算符)
- 基类的友元函数(friend修饰的函数)
注意一般继承类型选择public,少用private和protected,因为使用对应的修饰符,基类的成员在派生类中将变成对应修饰符的权限级别。如使用private,则基类的public和protected成员,在派生类也会private化。
12345678class <sub-name>:<visit><base1>,<visit><base2>{...};//示例class Rectangle:public Shape,public PaintCost{...};重载运算符和重载函数
函数重载也就是Java之类的面向对象里的方法重载,既同一个方法名,不同的方法签名。
- 运算符重载
12345678Box operator+(const Box&);//格式如上,必须有operator关键字,内部传入引用//如此box1+box2就被如下重载定义Box operator+(const Box& b){Box box;box.length = this->length + b.length;...}下面是可重载的运算符列表:
| + | - | | / | % | ^ |
| —- | —- | —- | —— | —— | ——— |
| & | | | ~ | ! | , | = |
| < | > | <= | >= | ++ | – |
| << | >> | == | != | && | || |
| += | -= | /= | %= | ^= | &= |
| |= | = | <<= | >>= | [] | () |
| -> | ->* | new | new [] | delete | delete [] |下面是不可重载的运算符列表:
::
、.*
、.
、?:
多态
面向对象编程语言三大特性,封装、继承、多态。
所谓多态,也就是一个方法或属性,在不同的派生类那里,有不同的具体表现方式。
但是C++语言里,需要派生类实现的抽象方法,需要使用关键字
virtual
在基类中修饰,不然的话,子类调用的仍然还是父类方法,而不是自己的具体实现:1234567891011121314151617181920212223242526272829class Shape{...public:...//此处若不用virtual修饰,那么子类实现该方法,调用时候,就依然是该方法,而不是子类自己的实现virtual int area(){cout << "Parent class area:"<<endl;return 0;}}//示例子类class Circle{...public :...int area(){cout << "Circle class area:" << end;return 0;}}int main(){Shape *shape;Circle circle;//存储circle对象地址shape = circle;//调用,如果Shape类area()函数不用virtual的修饰,那么输出的只能是Shape类的方法,而不是子类Cirle的area()函数。shape->area();return 0;}使用virtual修饰的函数成为虚函数,如果虚函数没有方法体,则成为纯虚函数。
类似于Java中的抽象方法。
数据抽象与数据封装
数据抽象就是私有化数据变量,推外提供set、get方法。数据封装,也就是类似于C中的结构体,或者java中的bean对象类,封装一组数据和函数,成为一个实体类。
抽象类一个含有纯虚函数的类。也称为接口。
3、高级教程
- 文件和流
iostream
标准库,提供了cin
、cout
方法,而文件标准库fstream
提供了三种数据类型ofstream
、ifstream
、fstream
分别对应的是输出、输入、和同时具备输入输出的类型。
- 打开文件12//参数表示,文件路径和名称,读取方式void open(const char *filename,ios::openmode mode);
模式标志 | 描述 |
---|---|
ios::app | 追加模式 |
ios::ate | 打开文件,定位到末尾 |
ios::in | 读取 |
ios::out | 写入 |
ios::trunc | 若文件存在,打开前截断为0字节 |
这些模式可以结合使用,::
符号为域定位符号
- 关闭文件
close()
函数是fstream、ifsteram、ofstream对象的一个成员。
- 文件位置指针
istream和ostream都提供了对文件重新定位的函数功能。这些成员函数包括关于 istream 的 seekg(”seek get”)和关于 ostream 的 seekp(”seek put”)。
seekg 和 seekp 的参数通常是一个长整型。第二个参数可以用于指定查找方向。查找方向可以是 ios::beg(默认的,从流的开头开始定位),也可以是 ios::cur(从流的当前位置开始定位),也可以是 ios::end(从流的末尾开始定位)。
- 异常处理
try…catch ,throw,好像C++中没有throws关键字
也可以通过继承exception类,重载其what()
方法,来自定义异常类
动态内存
堆,程序中未使用,运行时动态分配的内存
栈,函数内部声明的变量,都在此。
new 和 delete 运算符,用于动态分配内存。new data-type
C 语言中有malloc()
函数,但是C++ 最好用new,因为它可以分配内存,而且还创建了对象。
数组动态分配内存
12345678910111213141516char* pvalue = NULL;//初始化指针为nullpvalue = new char[20];//请求内存delete [] pvalue;//删除pvalue指向的数组int ROW = 2;int COL = 3;double **pvalue = new double* [ROW];//为行分配内存//为列分配内存for(int i = 0;i<COL;i++){pvalue[i] = new double[COL];}//释放内存for(int i = 0;i<COL;i++){delete[] pvalue[i];}delete [] pvalue;对象的动态分配内存
类似普通数据的动态分配:1234567891011121314151617181920using namespace std;class Box{public ://创建对象时候调用Box(){cout<<"构造函数"<<endl;}//删除对象时候调用~Box(){cout<<"析构函数"<<endl;}};int main(){//声明分配内存Box* myBoxArray = new Box[4];//释放内存delete [] myBoxArray;return 0;}命名空间
有点类似包名,或者xml中的命名空间的概念,就是通过一个完整路径定位,来便于区分不同地方的相同名称的函数和类。
关键字namespace
123456789namespace namespace_name{//代码声明}//调用的时候name::code;//code代表函数,或者变量//需要在文件头使用using namespace指令来说明使用的是哪个空间//类似于导入包,可以导入单个类,也可以导入整个包,代码中直接使用某个函数,如下using std::cout;
命名空间可以定义在不同的文件中,成为不连续的命名空间。还可以嵌套。
调用时候用::
定位符
- 模板
c++ 的模板也就是泛型,可以这么理解123template <class type> ret-type func-name(parameter list){//body code}
示例:
以上是函数模板,类模板也差不多
- 信号处理
C++ 中多了信号处理,在文件中
信号 | 描述 |
---|---|
SIGABRT | 程序的异常终止,如调用 abort。 |
SIGFPE | 错误的算术运算,比如除以零或导致溢出的操作。 |
SIGILL | 检测非法指令。 |
SIGINT | 接收到交互注意信号。 |
SIGSEGV | 非法访问内存。 |
SIGTERM | 发送到程序的终止请求。 |
- signal()函数1234567891011121314151617181920212223242526272829303132void (*signal (int sig,void (*func)(int)))(int);//第一个参数证书,代表信号编号,第二个是指针,指向信号处理函数。//示例:using namespace std;void signalHandler( int signum ){cout << "Interrupt signal (" << signum << ") received.\n";// 清理并关闭// 终止程序exit(signum);}int main (){// 注册信号 SIGINT 和信号处理程序signal(SIGINT, signalHandler);while(1){cout << "Going to sleep...." << endl;sleep(1);}return 0;}//此时,运行循环,用ctrl c来终端,就会被捕获信号。
raise()函数,生成信号int raise(signal sig);
//sig表示信号编号,
- 多线程
多任务计算机分为两种,基于进程和基于线程。基于进程的多任务是程序的并发执行;基于线程的多任务是同一程序的片段并发执行。
常见操作系统多是用POSIX编写线程。
1、创建12345678pthread_create (thread,attr,start_routine,arg);//参数,thread为指向线程标识符的指针,attr为不透明的属性对象,用来设置线程属性,可以设置NULL//start_routine线程运行起始位置,创建线程就被执行。arg运行函数的参数,//可以NULL,但是必须把引用作为指针转换为void类型传入。//终止线程pthread_exit(status);//一般不用显式调用,
实例:
连接和分离线程
//效果