泛型编程强调的是独立于特定的数据类型。
C++是C语言的超集。
动态链接库 DLL(Dynamic Linker Library):可以把DLL看做是一个仓库,它提供了一些可以直接拿来用的变量,函数或者类(但是不建议从DLL中获取变量),在历史的发展中,仓库经历了从“无库 - 静态链接库 - 动态链接库”的时代。静态链接库(.lib)和动态链接库(.dll)都是共享代码的方式。如果采用了静态链接库,则无论你愿不愿意lib中的代码指令都被直接包含进了最终生成的.exe程序中。但若是使用了动态链接库,该DLL则不会被包含进.exe程序中,当.exe程序执行的时候,再“动态”的来引用或者卸载DLL。
#include <iostream> //预处理器将iostream文件的内容添加到程序中(预处理操作:在源代码被编译之前,替换或添加文本) using namespace std;//输入输出工具cin/cout //若不加上句,则如下: std::cin >> n; std::cout << n << std::endl;
命名空间namespace同名时,命名空间::名称来区分。
//当包含多个命名空间时,用如下声明 using std::cout; using std::endl; using std::cin;
插入运算符<<与按位左移运算符<<属于运算符的重载。
控制符endl:重起一行。
#include <cmath> cout << endl;//cout << "\n";
函数声明:
void simon(int n); //函数声明 int stonetolb(int sts);
面向对象编程(OOP)的本质是设计并扩展自己的数据类型。
变量名字母数字下划线,数字不做第一个字符,区分大小写,不能使用关键字,不限长,多个下划线保留使用。
类型占字节
- short 至少16位,
- int 至少与 short 一样长,
- long 至少32位,且至少与 int 一样长,
- longlong 至少64位,且至少与 long 一样长。
符号常量
#include<climits> //limits.h 最大最小值
sizeof 是运算符,可查看类型或变量所占用的字节数,类型名需放在括号中,变量均可。
赋值,可用圆括号形式赋值。
int emus(7); int emm{7}; int emn = {8}; int rocs = {};//赋0 unsigned short sue = 0;
第一位是0,第二位为1~7位8进制,0x为16进制。
int cheat = 42; int waist = 0x42; int inseam = 042; cout << "cheat = " << cheat <<" in dec."<< endl; cout << "waist = " << waist <<" in hex."<< endl; cout << "inseam = " << inseam <<" in oct."<< endl; cout << hex;//十六进制打印 cout << "cheat = " << cheat <<" in hex."<< endl; cout << dec;//十进制打印 cout << oct;//八进制打印
数组赋值
只有在定义数组时才可以初始化,此后可以用下标分别给数组元素赋值,
不能将一个数组赋值给另一个数组,
初始化数组时提供的元素可以少于数组元素数目。
long total[500] = {0}; //初始化为0{} short things[] = {1, 5, 8}; //数组有3个元素
字符串以空字符结尾,空字符被写作\0,其ASCII码为0。
char dog[5] = {'b',' ','c','e','I'}; //字符数组 char cat[5] = {'a','c','f','s','\0'}; //字符串
字符数组初始化为字符串,只需使用一个用引号括起的字符串即可。
char bird[11] = "Mr. Cheeps";//隐式的包括结尾的空字符 char fish[] = "Bubbles";
字符串常量与字符常量
字符常量 字符串常量 形式 单引号引起的一个字符,’S’ 双引号引起的若干字符,”S”表示字符S和\0 含义 相当于一个整型值,可参加表达式运算 表示字符串所在的内存地址 字符常量可以赋值给字符变量,char b=’a’ 字符串常量不能赋值给字符变量 占内存 占一字节 若干字节,至少一个字符结束标志 strlen()计算字符串长度时不计入结束字符。
cin将空白字符(空格、换行、制表)作为结束符(忽略空白字符)。
istream中的类(如cin)提供了一些面向行的类成员函数:
getline()
和get()
,每次读取一行字符串输入:getline(),丢弃换行符;get()换行符保留在输入序列中。cin.getline(name,20) /* 最多读19个字符,余下空间存储自动在结尾处添加的空字符, 读取指定数目的字符或遇到换行符时停止 两个参数,第一个存储输入行的数组的名称,第二个是要读取的字符数 */ cin.get(name1,20);//name为字符数组 cin.get(name2,20);//a problem //由于第一次调用后换行符留在输入队列中,因此第二次调用时看到的第一个字符便是换行符。因此get()认为已到达行尾。 char ch; cin.get(ch);//单个字符
不带任何参数的
cin.get()
调用可读取下一个字符(即使是换行符)。cin.get(name1,20);//数字和字符串交替输入时,用cin.get()消耗掉回车符 cin.get(); cin.get(name2,20);
另一种是将两个类成员函数拼接起来(合并)。
cin.get(name,Arsize).get(); //cin.get(name,Arsize)返回一个cin对象,该对象随后用来调用get()函数。 (cin >> year).get(); /* cin >> year; cin.get(); */
函数重载:函数名相同,函数的参数不同。
string类:提供了一种将字符串作为一种数据类型的表示方法,而不是字符数组来存储字符串。
要使用string类,必须在程序中包含头文件string,
string类位于名称空间std中,
使用string对象的方式与使用字符数组的方式相同,
可以使用cin来将键盘输入存储到string对象中,cout来显示string对象,
数组表示法来访问存储在string对象中的字符。
主要区别:可以将string对象声明为简单变量,而不是数组
类设计让程序能够自动处理string的大小,方便安全
赋值:可以将string对象赋值给另一个string对象,而字符数组不可以互相赋值
拼接:可以用运算符+将两个string对象合并起来,+=将字符串附加到string对象末尾
string的其他操作:c++新增string类之前,使用c语言库中的函数来完成C-风格字符串的操作,头文件cstring(以前为string.h)提供了这些函数。
strcpy(char1, char2);//copy char2 to char1字符数组赋值 strcat(char1, char2);//append contents of char2 to char1追加
string类I/O
char charr[20]; cin.getline(charr, 20);//istream中cin类提供的成员函数 int len1 = strlen(charr); //==================================================// string str; getline(cin, str);//string类的方法 int len2 = str.size();
结构体struct:同一结构可以存储多种数据类型的数据
struct inflatable//声明结构体类型 { char name[20];//std::string name; float volume; double price; }; struct student { char name[20]; float weight; double height; } infor = { "guluyu", 56.5, 178.5 }; //结构体对象/变量,也可创建结构体时创建结构体对象并初始化 inflatable guest = { "Glorious Gloria", 1.88, 29.99 }; //C++允许在声明结构变量时省略关键字struct guest.name;//通过成员名可以访问结构的成员 guest.name[0]; inflatable choice = guest;//结构体可以用赋值运算符初始化
C++推荐使用局部变量,外部(全局)结构体。
结构数组:数组中的每个元素都是结构体。
student informantion[2] = { {"gulu", 55, 176}, {"fish", 60, 180}, } ; cout << informantion[0].name << " is " << informantion[0].height << " cm and " << informantion[0].weight << " kg." << endl;
c++位字段允许指定占用特定位数的结构成员,用于硬件寄存器数据结构的创建。
共用体/联合体(union)可以存储不同的数据类型,但只能同时存储一种数据类型,共用内存空间,长度为其最大成员的长度。
union one2all { char ch; int n;//共用体占四字节,取大 }; one2all num; cout << "sizeof(num) = " << sizeof(num) << endl; num.ch = 'A'; cout << "num.ch = " << num.ch << endl;
枚举:可进行连续多个的符号常量赋值,代替const 。
enum spectrum{red, orange, yellow, green, blue}; //spectrum为新类型名,内容为符号常量,依次为0~4 spectrum band; band = blue; int color = blue;//枚举型可提升为int型。
指针存储值的地址,指针名表示地址。
*运算符
被称为间接值或解除引用运算符,取值运算符。&取址运算符。指针的危险: 在对指针的内容修改之前,一定要将指针初始化为一个确定的、适当的地址。
内存分配:new运算符,返回开辟空间的首地址。指针可在运行阶段分配未命名的内存以存储值。
为一个数据对象获得并指定分配内存的通用格式:
typeName *point_name = new typeName;
new分配的内存块通常与常规变量声明分配的内存块不同,常规都存储在栈中,而new从被称为堆或者自由存储区的内存区域分配内存。
new可能会导致内存被耗尽,可以使用delete释放内存。delete和new要配对使用,否则内存泄漏,不可以释放已经释放的内存块,不能使用delete释放声明变量所获得的内存。
int *ps = new int; delete ps;//只是释放ps指向的内存,并不会删除指针ps本身 int *psome = new int [10];//使用new创建动态数组 delete [] psome;//释放整个数组,如果不加方扩号只释放指针指向的第一个元素,即首元素(不可以)
使用
new
和delete
时,遵守规则:不要使用delete来释放不是new分配的内存
不要使用delete释放同一个内存块两次
如果使用new[ ]为数组分配内存,则应该使用delete[ ]来释放
如果使用new[ ]为一个实体分配内存,则应使用delete(没有方括号)来释放内存
对空指针应用delete是安全的
指针和动态数组基本等价:指针算术和C++内部处理数组的方式。将指针变量加1后,其增量的值等于指向的类型占用的字节数。
double *p3 = new double[2]; p3[0] = 0.2; p3[1] = 0.5; p3 = p3 + 1;//指针可以,数组不可以
如果cout输出指针,将打印它的地址,但如果指针类型为char*,则cout将显示指向的字符串。如果要显示字符串的地址,则必须将这种指针强制转换为另一种指针类型。
char animal[20] = "bear"; const char * bird = "wren"; char * ps = animal; cout << animal << " and " << bird << endl; cout << animal << " at " << (int *) animal << endl; cout << ps << " at " << (int*) ps << endl;
应使用strcpy()或strncpy(),而不是赋值运算符来给字符串赋给数组。
自动存储、静态存储、动态存储、线性存储
模板类
vector
类似于string类,也是一种动态数组。#include<vector> using namespace std; vector<int> vi; int n; cin >> n; vector<double> vd(n);
模板类
array
,长度固定使用栈(静态内存分配)。#include<array> using namespace std; array<int, 5> ai;//固定 array<double, 4> ad = {1.2, 2.4, 3.7, 5.5};
当用字符数组接收时用
cin.getline(name, size);
当用string接收时用
getline(cin, str);
cout在显示bool之前将它们转换为int,但
cout.setf(ios::boolalpha)
函数调用设置了一个标记,该标记命令cout显示true和false,而不是1和0。递增/递减运算符和指针
double arr[5] = {21.1, 32.8, 23.4, 45.2, 37.4}; double *pt = arr; cout << *pt << endl; cout << "*++pt = " << *++pt << endl; //前缀递增/递减与取值运算符*优先级相同,优先级一样时从右到左,32.8 cout << "++*pt = " << ++*pt << endl; //33.8 cout << "(*pt)++ = " << (*pt)++ //后缀,先括号,取出32.8(上述表达式已将指针后移),再执行++,33.8 << ", *pt = " << *pt << endl;//后++,34.8 cout << "*pt++ = " << *pt++ //后缀优先级优于前缀,先取出*pt值,然后pt++是加在地址上,34.8 << ", *pt = " << *pt << endl;//23.4
关系运算符的优先级比算数运算符的低。
C++为类型建立别名的方式有两种
- 预处理器:不能声明一系列变量
#define BYTE char
typedef typeName aliasName
- 预处理器:不能声明一系列变量
基于范围的for循环(C++11),对数组(或容器类,如vector和array)的每个元素执行相同的操作。
头文件iostream将cin.get(ch);的参数声明为
引用类型
,因此可以修改其参数的值。文件尾条件——检测文件尾(EOF)
while(cin.fail() == false)//cin.fail()为true时文件结束,判断输入是否结束,win下ctrl+Z,unix为ctrl+D //cin.clear();可以清楚EOF标记,使以后输入继续进行
变量写在右侧,常量写在左侧更佳
if(3 == myNumber)
逻辑运算符
运算符 描述 实例 && 逻辑与运算符。两个操作数都 true,则条件为 true (A && B) 为false || 逻辑或运算符。两个操作数中有任意一个 true,则条件为 true,左为真则不判断右 (A ||B) 为 true ! 逻辑非运算符。用来逆转操作数的逻辑状态,条件为 true 则将使其为 false !(A && B) 为 true cctype
中的字符函数#include<cctype>/* C++从C语言中继承了一个与字符相关的函数库(cctype),它可以确定字符是否为大写或小字母、数字、标点符号等工作,这些函数包含在以下头文件中*/ char ch; bool yes = isdigit(ch);
条件运算符
?:
输入内容和类型不匹配:
n的值保持不变
不匹配的输入将被留在输入队列中
cin对象中的一个错误标记被设置
对cin方法的调用将返回false
cin.clear();//重置错误输入标记,同时也重置EOF条件 while(cin.get() != '\n');//消耗输入队列中的错误内容
简单文件的输入/输出
#include<fstream> //1.头文件 ofstream ifstream ofstream outFile; //2.创建输出流对象 //输出流对象用法同cout outFile << fixed;//小数 outFile.precision(2);//两位精度 outFile.setf(ios_base::showpoint);//显示小数点后0 outFile.open("carinfo.txt");//3.将对象和文件关联起来,文件路径 outFile << "Make and model: " << automobile << endl; ifstream inFile;//输入流
综合实例
#include<iostream> #include<fstream> #include<cstdlib>//使用到exit(); using namespace std; const int SIZE = 60; int main(void) { char filename[SIZE]; ifstream inFile; ofstream ouFile; ouFile.open("score.txt"); ouFile << "350 360 380 408 292 319\n985 211 900" << endl; cout << "Enter name of data file:"; cin.getline(filename, SIZE); inFile.open(filename); if(!inFile.is_open())//打开失败时 { cout << "Could not open the file " << filename << endl; cout << "Program terminating." << endl; exit(EXIT_FAILURE); } cout << "Success open the txt file." << endl; double value, sum = 0.0; int count = 0; inFile >> value; while(inFile.good())//读取的数据是否可用 { ++count; sum += value; inFile >> value; } if(inFile.eof())//读到文件末尾 cout << "End of file reached." << endl; else if(inFile.fail()) cout << "Input terminated by data mismachted." << endl; else cout << "Input terminated by unknow reason." << endl; if(0 == count) cout << "No data processed." << endl; else { cout << "Items read: " << count << endl; cout << "Sum: " << sum << endl; cout << "Average: " << sum/count << endl; } inFile.close(); return 0; }
C++编程模块
函数传递成员变量时为其拷贝值,传递数组时为原来的数组。
int cookie[ArSize] = {1, 2, 4, 8, 16, 32, 64, 128}; int sum = sum_arr(cookie, ArSize); //数组名视为指针,解释为第一个元素的地址,对数组名sizeof得到整个数组的长度(字节) //为将数组类型和元素数量告诉数组处理函数 int sum_arr(int arr[], int n);//数组表示法 int sum_arr(int *arr, int n);//指针表示法 int sum = sum_arr(cookie, cookie+8);//区间的方式 int sum_arr(const int *begin, const int *end)//第一个与最后一个的后一个位置 arr[i] == *(arr + i); &arr[i] == arr + i;
为使操作不修改原数组,可使用
const
。void show_array(const double arr[], int n); const int *pt;//read-only,pt指针的指向可自定义,但不能通过这个指针修改所指的内容 int *const pt;//可通过指针修改所指内容,但是不能更改指针的指向 const int *const pt;//指针只能指向一个变量,并不能通过该指针修改内容
二维数组和结构体:获取结构的地址,必须使用地址运算符&,与数组不同,数组名即为首地址
int sum(int (*ar2)[4],int size);//括号不可少,size为行,4为列 int sum(int ar2[][4], int size); struct polar//极坐标 { double distance; double angle; }; polar rect_to_polar(rect xypos); void show_polar(polar dapos); void rect_to_polar(const rect *xy, polar *pda); void show_polar(const polar *dapos);
引用变量
用途:作为函数参数,结构和对象参数,不可以是常量;
必须在声明引用变量时进行初始化;
如何实参和引用参数不匹配,C++将生成临时变量,仅当参数为const引用时才可以。
int rats; int & rodents = rats; //这里&不是地址运算符,而是类型标识符的一部分int &是指向int的引用 //上述声明允许将rats和rodents互换——它们指向相同的值和内存单元,相当于同一变量的两个名称
应尽可能使用const
- 可以避免无意中修改数据的编程错误
- 使函数能够处理const和非const实参,否则将只能接收非const数据
- 使函数能够正确生成并使用临时变量
继承:使得能够将特性从一个类传递给另一个类的语言特性叫做继承。
- 派生类继承了基类的方法
- 基类引用可以指向派生类的对象而无需进行强制类型转换
重载:重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明,但是它们的参数列表和定义(实现)不相同。
左值引用,可取地址;否则用const修饰作为常引用
int a = 10;//a为左值,10为右值 //int &c = 10;//invalid const int &d = 10; const int &c = (a+b);
C++11引入了右值引用,为了支持移动
int &&x = 10; int &&y = (a+b);
函数模板:使用泛型来定义函数。
如此编写,但编译后最终仍将由独立的函数定义,可将函数模板放在头文件中。
template<typename T> void Swap(T &a, T &b); template<typename T> void Swap(T a[], T b[], int n);//模板重载 template<typename T>//typename = class void Swap(T &a, T &b) { T temp; temp = a; a = b; b = temp; }
评论