English words
- literal:常量
- default argument:默认参数
- assigned to:赋值
- square brackets:方括号内
- parenthese:圆括号
- brace:大括号
- underscore:下划线
- encapsulated:封装
- initialize:初始化
- inerface:接口
- ternary operator:三元运算符:(A?B:C)
- pointer arithmetic 指针算数
- indirection operator:'*'
- subscript:下标
- modify:修改 specify: 明确定义
- pseudocode:伪代码
- encompasses:包含
- block:代码块 {int a="19.06"}
- Terminate with a semicolon(分号):以分号结束
- stack:栈
- Manipulat:操作
- argument:参数、自变量
- include guard
- object of the same class 类的实例化对象
- terminate 终止
- derived class 派生类
- instantiate 实例化
- insertion 输入
- extraction 输出
- cascated 连续调用
- delimiter 终止符
- truncated 截取的,缩短的
- generic programming: 泛型编程
选择题话术
-
Software (i.e., the instructions you write) controls hardware (i.e., computers).
-
A multi-core processor implements several processors on a single integrated-circuit chip.
-
ASCII is a popular subset of Unicode
-
Interpreted programs run slower than compiled programs.
-
C++ functions other than main are executed:When they are explicitly called by another function
-
the name of the values the method call passes to the method for the parameters:argument
-
Specifying the order in which statements are to be executed in a computer program is called: Program control
-
An uninitialized local variable contains: The value last stored in the memory location reserved for that variable
-
Having a loop within a loop is known as: nesting
-
break and continue statements alter the flow of control: "break" 和 "continue" 语句改变控制流程
-
Converting from type int to type char will result in the loss of data
-
The preceding include guard prevents the code between #ifndef (which means “if not defined”) and #endif from being included if the name TIME_H has been defined.
-
Outside a class’s scope, public class members are referenced through one of the handles on an object—an object name, a reference to an object or a pointer to an object.
-
The object or built-in array is created in the free store (also called the heap)—a region of memory assigned to each program for storing dynamically allocated objects.
-
many of the other for statements in class Array’s implementation with the C++11 range-based for statement. Unfortunately, range-based for does not work with dynamically allocated built-in arrays.
-
A class-scope variable hidden by a block-scope variable can be accessed by preceding the variable name with the class name followed by::
-
Every object of the same class gets a copy of every member variable
-
There is mechanism in C++ for a constructor to call another constructor in the same class. [C++ includes delegating constructors—that is constructors that can delegate their work to other constructors in the same class.]
-
A destructor does not releases the object’s memory.
-
The constructor for a static local object is called only once, when execution first reaches the point where the object is defined.
-
In an is-a relationship, an object of a derived class also can be treated as an object of its base class.
-
Many languages use alphabets that contain more characters than a single-byte char can represent. The ASCII character set does not provide these characters; the Unicode character set does. Unicode is an extensive international character set that represents the majority of the world’s “commercially viable” languages, mathematical symbols and much more.
-
In cpplib , both unformatted- and formatted-I/O services are provided.
-
The typedef iostream represents a basic_iostream that enables both char input and output.
-
Outputs to object cerr are unbuffered, implying that each stream insertion to cerr causes its output to appear immediately—this is appropriate for notifying a user promptly about errors.
-
Function eof returns true only after the program attempts to read past the last character in the stream.
-
If the specified file does not yet exist, then the ofstream object creates the file, using that filename.
-
Prefix increment has slightly more overhead than postfix increment. 前置递增的开销比后置递增大
-
Based on whether an operator is implemented as a member function or as a non-member function, the operator is used same in expressions.
-
The colon ( : ) in the header of the class definition indicates inheritance.
-
A base-class constructor's default arguments are not inherited. Instead, the compiler generatesoverloaded constructors in the derived class.
-
Downcasting enables Making a base-class pointer into a derived-class pointer
- dynamic_cast is often used to Downcast pointers
-
C++ files include information about their structure.
-
When opening a file, you can specify the name of the file as either a pointer-based string or a string object.
-
A random access file is organized most like an Array.
-
generic programming: class templates enable you to conveniently specify a variety of related (overloaded) function
-
Default type parameters must be the rightmost (trailing) parameters in a template’s type-parameter list.
-
Variables, classes and functions in an unnamed namespace are accessible only in the current translation unit (a .cpp file and the files it includes).
-
The typedef istream represents a basic_istream that enables char input. The typedef ostream represents a basic_ostream that enables char output. The typedef iostream represents a basic_iostream that enables both char input and output.
-
The typedef ifstream represents a specialization of basic_ifstream that enables char input from a file. The typedef ofstream represents a specialization of basic_ofstream that enables char output to files. The typedef fstream represents a specialization of basic_fstream that enables char input from, and output to, files.
类
class定义的末尾要加上分号
- 类的属性(attribute):数据成员(data member), aka成员变量
- 类的成员函数定义后面加const 如:void message() const 这可以防止该函数修改class的数据成员
- class中的数据默认是private
- 类的构造函数(constructor)和析构函数(destructor):构造函数的名称必须与类同名,理论上来说可以放在private里面; default constructor:默认构造函数
- explicit:显式构造函数,防止参数传递的时候发生隐式类型转换:比如说double转成int
- 构造函数可以是有参,也可以是无参,不能有返回值
- 自定义了构造函数,实例化就必须调用对应的参数列表
- 构造函数可以用于类的初始化,但函数中的形参与类的属性无关,构造和析构函数的末端不能加const
- 析构函数不能接收任何的参数,也不能返回任何的值
- 构造函数可以多次重载,一个类只能有一个析构函数函数,而且必须放在public作用域内
- 构造函数可以调用自己类的构造函数的重载版本(Delegating Constructors)
- 析构函数本身不释放内存,而是进行一些清理的工作
class one
{
explicit one();
~ one();
};
void test(){
one o();
}
//Delegating Constructors
Time::Time()
Time( 0, 0, 0 ) //delegate to Time( int, int, int )
{
} // end constructor with no arguments
Time::Time( int hour )
Time( hour, 0, 0 ) //delegate to Time( int, int, int )
{
} // end constructor with one argument
- 定义类:可以防止双重定义,使用ifndef或者pragma once
#ifndef TIME_H
#define TIME_H
...
#endif
//这个叫做include guard
# pragma once
- 对象实例化方式:
1. Time t(a,b,c)
3. Time t={a,b,c}//list initializers
4. Time sunset;
5. array <Time,5> arrayOfTimes;//类数组初始化
6. Time &DinnerTime= sunset;//引用初始化
7. Time *timePtr=&DinnerTime;//指针初始化
8. array[0] = new Time(2,1,3)
- 调用构造/析构函数的时期:
- 在全局区的类:在所有函数调用之前构造,在最后析构
- 关于“最后”: main函数执行结束,一般有两种异常:
- exit(),when a fatal unrecoverable error occurs
- abort(),indicate an abnormal termination of the program
- 关于“最后”: main函数执行结束,一般有两种异常:
- 在local区的类:在local区构造和析构
- 静态局部对象(static class c)(对应的构造函数只执行一次):在定义的时候就构造,遇到exit()析构,遇到abort()不析构
- staic and global的析构调用顺序为先static后global
- 在全局区的类:在所有函数调用之前构造,在最后析构
- 返回私有数据成员的引用或者指针,会破坏私有性,该引用或者指针能够修改私有的数据成员
- 公有成员函数可以返回对应的私有数据成员的引用
public: int & geta(){ return a;} priavet: int a; - 可以通过构造函数逐一赋值:
Time::Time(int a, int b)
:date(a),month(b){}
- 类中的拷贝构造函数:
- Person p2(p1): 注意实现的时候不能通过指针地址传递实现
- 深拷贝与浅拷贝:是否在代码中写出来
- 一定要调用对象的引用,否则会无限构造
- 拷贝函数 =delete :防止调用拷贝构造函数
class(const class &); //应当为const引用,保证可以复制const对象
{
ptr= new int(var); //浅拷贝
}
class a=b//调用默认拷贝构造函数
- 转换构造函数(conversion constructor: single-argument construcors)
- 可以在user-defined types之间转换
- 不会被编译器隐式生成(如果没有显式定义)
- 常用于将内置类型转换为user-defined
MyClass::operator char *() const; //将MaClass类转换为char *类,没有返回类型
- 静态成员变量:所用成员共享
- 类内声明,类外初始化(C++ 11 允许int和enum类型的静态成员类内初始化)
- 静态成员函数:共享
- 静态成员函数,不可以访问非静态成员变量
- 空对象占用内存为1,只用非静态成员变量属于某个对象,其他:静态成员变量,非/静态成员函数都不属于某个对象
- 访问:
- public 在类内可以自由访问,类外也可以通过类名、引用、指针的方式访问
- private 类外要通过静态的成员函数进行访问,类内可以自由访问,友元函数也可以访问
- 不能在静态成员函数中使用this指针
- 静态成员变量不能在成员函数(包括静态成员函数)内进行初始化, 也不可以在类的构造函数中初始化
class A{
public:
static void test1();
private:
static int b;
};
int A::b=1;
void A::test1(){
b=2;
}
- 只用常对象能够访问常成员函数:
- 常成员函数: void func() const
- 常成员函数不能调用非const成员函数
- 常数据成员可以通过构造函数初始化
- 构造和析构函数不能声明为const
const Time noon(a,1,2);
- mutable:修饰类的成员变量,使得该成员变量能够在const成员函数,const对象中被修改
- 如果没有mutable,那么要修改const的成员函数就要用const_cast
class testmutable{
private:
mutable int a=0;
public:
int changea() const{
return ++a; //合法
}
}
- Dot (.) and Arrow (->) Member Selection Operators:
- dot: 引用的访问
- ->: 指针的访问
- 对于public的数据成员,可以直接通过指针/引用/对象进行访问
- 访问函数与助手函数
- Access functions can read or display data. Another common use for access functions is to test the truth or falsity of conditions
- Utility Functions is a private member function that supports the operation of a class’s other member functions, for developers.
- 关于使用等号赋值:
- 如果不想要通过赋值被修改,就要加上const
p1=p2 // 可以将p2的值全部逐个赋值给p1,使用的是p2的副本,但不能够解决动态分配内存的指针的问题
- 对象作为类成员:(composition, has-a relationship)
- 对应的类成员也要在构造函数那里进行初始化
- 先初始化composition(顺序由在类中的定义决定,不由构造函数调用顺序决定), 再初始化类对象, 析构反之
public:
Employee(const class a, const class b, double d)//这里尤其要注意:在进行类的实例化的时候,因为传递的是临时化的对象,所以会出现两个编译器自动调用的拷贝构造函数
: composition1(a),composition2(b),d(d){}
private:
class composition1;
class composition2;
double d;
- 与composition对比理解: is-a relationship: 继承 只有公有继承才是is-a relationship,私有和保护继承不是
- this指针:本质是一个访问类自己地址的指针
- this的类型:
- 非const成员函数: 指针常量
- const成员函数:常量常指针
- 作用:可以在命名重复的时候访问到类的成员
- *this: 对象本身
- *this 可以让类串联函数调用
- this的类型:
class t{
public:
void A(){return *this;}
void B(){return *this;}
void C(){return *this;}
};
void a(){
t T;
T.A().B().C();
}
- 在类内的成员函数中,如果定义了一个新的类的实例化,那么这个实例化拥有class scope
- 可以将 (函数、类、成员函数) 作为类的友元
friend class ClassTwo; //类
friend void setx(); //函数
friend void ClassTwo:: setx(); //成员函数
- 友元的关系不传递也不对称(单向)也没有继承性(基类的友元不会继承给继承类)
- 友元性质与在类的位置无关
- 访问方式:通过实例化一个类的对象进行访问:
class A{
friend void seta(A &);//注意要传入一个类的引用
private:
int a=0;
};
void seta(A &AA){AA.a=1;} 其他的也一样
- 友元函数可以重载,每次重载必须清晰写出对应的声明
- 派生类的友元函数可以访问派生类对应的基类里面的public, protected的数据成员, 但是需要通过实例化的对象进行访问
- 继承语法
class father{};
class sun: public father{} 公有继承,父类中公有的和保护的内容在子类中不变 public还是public, private还是private
class sun: protected father{} 保护继承,父类中公有的和保护的内容在子类中为保护
class son: private father{} 私有继承,父类中公有的和保护的内容在子类中为私有的
- 父类中的private部分会被继承,但是是被隐藏了,无法直接通过子类访问
- 解决方案:写get,set函数
- 将private写道protected里面,能够直接访问
- 保护权限类外无法访问
- 构造析构顺序:构造是从子类推到父类,析构则是从父类推回到子类(先进后出)
- 如果父类中的成员属性/成员函数与子类中的同名,如果是通过子类的对象进行访问,那么直接访问的就是子类的函数,那么访问父类的时候要加作用域 是否是静态的都一样
//子类中
int getsalary(){
return base::getsalary+bonus;
}
- 构造、析构函数和重载的赋值运算符不能被继承
- 派生类构造函数需要显式调用基类的构造函数, 如果没有显示调用,编译器会自动调用隐式的构造函数,但是如果我们在基类自己写了一个构造函数(无论是什么构造函数都一样),那么编译器就不会生成一个默认的构造函数了,因此就会编译错误
baseplus(const string &first, const string &last, double sales,double rate, double salary)
: base(first,last, sales, rate) //显式调用
{}
- 在C++11中,可以直接继承基类的构造函数,但是要注意:只会调用默认的构造函数
- 构造函数的public、private、protected的性质默认由基类决定
class B: public A{
public:
using A::A;//使用继承构造函数
};
- 区分多个同名数据成员的方法:
- 加上作用域(::)来区分对应的同名类成员
- 用基类的指针接收派生类的对象
class son: public father1, public father2{
public:
son(int a,int b, int c)
: father1(a),father2(b),c(c){}//这里构造函数的顺序是根据class son: public father1, public father2的顺序决定
private:
int c;
};
int main(){
son s(a,b,c);
s.father1::func();
s.father2::func();
}
- 可能会遇到不同的重载的副本:使用virtual 多态进行解决
class son:virtual public father
- 静态:地址在编译阶段绑定(了解)
- 动态:地址在运行阶段才绑定: 父类的指针或者引用指向子类
- 多态通过指针或者引用实现,而不能通过类名实现
- 如果子类重写了父类的虚函数,派生类中的虚函数表内部会替换成为基类虚函数的地址
- 一定要用指针/引用调用虚函数
- 如果没有写成虚函数,那么用基类的指针指向派生类的对象就会调用基类的数据成员(前提是这个数据成员在基类和派生类中都存在)
- 本质:如没有写成多态的形式,那么指针类型决定了调用哪个类的数据成员
- 子类的函数中virtual 和 override 可以省略
- 在某种程度上来讲,派生类对象可以通过基类进行处理,而基类的对象不能通过派生类进行处理
- 利用基类指针,编译器只允许调用基类的成员函数,即使基类的指针指向派生类对象,也不能调用派生类的成员函数
- 解决方案: downcasting: 强制类型转换: 危险的操作
Son s1;
Father* f = &s1;
Son *s = (Son*)f;
s->print1(); //调用派生类成员函数
- 使用方法: 多态
virtual void function() const {} //这个是基类的虚函数
virtual void function() const override{} //这个是派生类对应的虚函数,注意const必须写在override前面
- 如果是虚函数,那么可以通过使用基类的指针完成对于派生类的函数的调用
- override的函数必须有相同的函数签名和对应的返回值类型
- 如果派生类没有重写对应的虚函数,那么直接继承基类的
- override的作用:编译器检查该函数是否是虚的,不是就报编译错误
- final: 告诉编译器这是函数的最终版本,接下来不能修改该函数,任何修改操作都是编译错误
- 甚至可以将类定义为final,防止对应的类被当作基类
virtual int name() = 0; 加入等于0
- 能够避免编写没有明确目的的函数
- 存在纯虚函数,那么该类为抽象类:
- 无法实例化对象
- 如果子类不重写纯虚函数,子类也无法实例化对象
- 有完整的实现的类就是完整类(concrete classes),能够实例化对象
- 能够作为指针或者引用的句柄,指向派生类
- 纯虚函数也可以有具体的实现的代码
构造函数不能写虚函数
- 如果类里面存在虚函数的时候,建议destructor也写为虚析构,这样避免调用析构函数时无法delete 对应的指针
- 纯虚析构和纯虚函数性质类似,但是纯虚析构需要有具体的代码实现
- 虚析构可以用父类指针完全释放子类的内存
- 如果在头文件的构造函数中写了默认参数,那么在源文件就不用写了
- 虚函数没有实例化,不能够被调用
- 如果派生类也是抽象类,就可以不用重写纯虚函数
virtual ~class() override{}//虚析构
virtual ~class() =0; //纯虚析构 !!!纯虚析构必须有对应的实现
类外: class::~class(){}
virtual ~pluscalss() override{}// 派生类写法
- static_cast:不检查当前对象,直接进行转化
- dynamic_cast: 检查当前的对象,并能够将指针类型转化
- 通过runtime来判断一个类的类型
//将基类employee指针转化为派生类的basepulsemployee baseplusemployee *ptr = dynamic_cast<baseplusemployee *> (baseptr) if(ptr!=nullptr){ }//如果基类指针对应的对象是baseplusemployee的话,就会返回对应的地址;如果不是,就会返回空指针 - 查看类型:typeid
# include<typeinfo> typeid(* baseptr).name() //typeid返回了一个type_info的引用,然后调用type_info类中的name()函数返回对应的类的名称
输入输出流
- 打印\n等特殊符号:cout<<"\n"<<endl; 输出结果:\n
- 等待对应时间后输出:使用sleep(1),指的是间隔1秒后输出,需要include<unistd.h>
- C++默认输出共6位(整数+小数部分)
- C++中检查字符串是否为空的函数:empty(), 使用substr截取字符串, 用at()访问对应下标位置的字符
- 头文件
- 基类:ios,派生类:ostream,istream,子子类:iostream,cerr/clog/cout : ostream对象
- cerr: 未缓冲的输出流,速度快
- clog: 缓冲的数据流,
- iomanip: 用于格式化输出
- fstream: 文件处理
- 基类:ios,派生类:ostream,istream,子子类:iostream,cerr/clog/cout : ostream对象
- 输出流:
- put():只能够输出一个字符,如果超过一个字符的2位数,就会转换成为Ascill码对应的值
cout.put('A').put('\n') //支持连续调用 cout.put(65)- char*
- 本来输出char *类型的指针应该输出对应的地址,但是C++将char *的输出定义为输出指针对应的值,因此要进行转化
const char* const ptr= "lalala"; cout<<static_cast<const void *>(ptr)<<endl; //void* 无类型指针,可以支持任何指针化为该指针
- 输入流:
- get和getline
//get函数有三个重载, get是从缓冲区拿走字符 while(cin.get()!=EOF){} ; // 读取输入的内容,直到用户输入文件结束符(Ctrl+Z) char c; while(cin.get(c)){}; //这里一定要为char string a; a=cin.get()//这个版本的get函数只读取一个字符,并返回对应的值 char ch[20]; char* cha; cin.get(ch,20,'\n')// 变量名,长度,对应的终止符(长度优先),默认为'\n',终止符不会被读入,读取到终止符前一个字符截止 //getline是读取到换行符结尾, getline会将delimiter从流中删除 cin.getline(var,length)- cin是读取到空白的输入符(比如space、enter等等)就停止读取,而get则是读取到Ctr+Z
- peek,putback,ignore
- ignore 忽略调输出的buffer里面的某些字符,比如说'\n'
cin.ignore(n,'\n');// 忽略n个字节,直到遇到'\n',就直接terminate终止- peek 查看并返回缓冲区的第一个字符,但并不取走
- putback 将get从缓冲区拿走的数据放回缓冲区
- get和getline
- read,write,gcount: 非格式化的I/O
- read/write格式
cin.read(var,length); cout.write(var,length);- cin.gcount() 返回最近一次输入操作所读取的字符数
- 流操纵符:
- 整形流的基数: dec(10进制),oct(8进制),hex(16进制),setbase(parameterized stream manipulator) all sticky
- showbase: 显示当前进制前缀: 16进制: 0x, 8进制:0; noshowbase, sticky
- uppercase/nouppercase: 表示数字的字母是否大/小写,默认为lowercase sticky
# include<iomanip>// setbase() int number =10; cout<<showbase; cout<<uppercase; cout<<oct<<number<<endl; cout<<setbase(10)<<number;- 浮点精度(precision,setprecision) sticky
- fixed,scientific:
- fixed:保持浮点输出(3.141592653589790000),
- scientif则是转化为科学计数法 (sticky)
- 关于length: 如果在输出前定义了fixed/scientific,那么length就是小数点后几位; 如果输出前没有定义fixed/scientifiic,那么length就是输出的有效数字
- fixed,scientific:
#include<iomanip> cout.precision() //调用无参数类型,返回对应输出几位有效数字 cout.precision(length) cout<<setprecision(length)- 域宽(width,setw) not sticky
- 对齐 justification (left,right,internal) not sticky, 默认是right(右对齐)
cin.width(); //无参数调用,返回当前的width的值 cin.width(5); cout<<setw(5);- 自定义操作
- 返回值一定要是ostream的引用
ostream& name(ostream &os){ return os<<"name";} cout<<name; - 整形流的基数: dec(10进制),oct(8进制),hex(16进制),setbase(parameterized stream manipulator) all sticky
- 流的格式状态和流操纵符:sticky
- 尾数零和小数点 trailing zeros and decimal points
cout<<showpoint; //输出当前精度的数,不省略0: 比如 9.9000,不showpoint就是9.9, showpoint之后就是9.9000 cout<<noshowpoint;- 内容填充 paddling (fill,setfill) sticky
- 默认填充' ',空格
cout.fill('*'); cout<<setw(10)<<'a'<<endl; cout<<setfill('~')<<setw(10)<<endl; //setfill和setw前后顺序不重要- specifying boolean format: 指定布尔格式: (boolalpha, noboolalpha) sticky
bool a= false; cout<<boolalpha<<a;- setting and resetting the format state: flags: 对于当前输出格式状态的存档,每一个flags对应一个固定的参数
ios_base::fmtflags originalFormat= cout.flags() //存档,没有参数的flags返回当前的设定的输出格式 cout.falgs(originalFormat);//使用该存档- showpos: 在输出之前加入 '+', noshowpos,不受setw()的影响 sticky
- 流的错误状态:
- cin.eof() 是否遇到文件结尾
- cin.fail() 发生格式错位,数据保留
- 只有read会设置failbit
- cin.bad() 发生数据丢失错误 状态位:failbit/badbit:istream/ostream的数据成员
- cin.good() 以上的状态为都没有被设置,这个改为true
- cin.rdstate() 返回流是否存在错误,没有就是false
- cin.clear() 清空状态位,全部复原
- 输出流连接到输入流
- 编译器可能会自动连接
cin.tie(&cout);
cin.tie(0) //解除绑定
- operator! 返回true如果badbit,failbit都被set了,而operator void * retrun false
- flush: 与endl用法类似,作用为刷新缓存区,能够清理缓存区的内存
- wchar_t 被设计用于存储Unicode 类型的数据
跳过空格、tab、newline等等 cin会返回istream对象的引用,对输入是否为空进行判断
函数
- 无形参函数:void func(void)
- 函数默认参数(default argument):在申明函数的参数时候就给出对应的值,如果调用函数的时候没有传递参数,那么就用默认参数,如果多个参数只传递了其中的一部分,就按从前到后的方式是赋值
- 内联函数 在函数定义前加inline: inline void a(),加速编译
- 函数:值传递、地址传递、引用传递 地址传递和引用传递传递的都是地址,会直接修改对应地址的值
- 引用传递 return-type fuction-name1(int &a)
- 地址传递 return-type fuction-name2(int *c)
- 值传递,实参的值不改变 fuction-name1(b);
- 函数的重载(function overloading):定义相同函数名的函数,但是为了处理不同的数据,所有声明签名不同的函数
- 返回值类型不同不能作为函数重载的条件
- 函数签名:函数名+形参表(每个程序中,函数签名应该是独一无二的),如果调用时无法区分,那么程序会自动报错,函数签名(signature):void func(int, double) 包括:返回值类型,函数名,形参表
- 函数原型(protopype),就是先定义函数,给出函数的返回值类型和函数名(形参可以不用定义),然后在后面继续定义函数
- 数组和指针的函数原型写法:
void name(int []) void name(int *) - 函数定义(definition): 包括函数头+函数体 函数定义形参的时候,有默认值的参数一定要写在最后,没有默认值的写在前
- 函数体中不能再定义新的函数
- 函数的强制类型转换:比如int与double的互换,隐式类型转化,但是可能会丢失精度
- 函数返回值类型为引用:比如: int& a(), 不能返回非静态成员变量,不能返回常量
- 函数的模板:template ,typename或者class都可以,typename和T之间不要加逗号!
- T(或返回值) 函数名(T a, T b)函数的模板能够在实际编译的过程中去识别具体的变量数据类型(或其他)
数组
- size_t: 无符号整型数据类型,size_t储存对象的索引,unsigned int 储存对象的值
- C++数组排序:sort(start,end)排序,需要inlucde库,就直接sort,不返回: sort(a.start(),a.end());
- auto关键字,自动识别类型, 不能够直接作为参数类型定义变量,需要作为接收的一方
- vecto容器:include vector初始化
vector<数据类型> 变量名={1,2,3};
vector<数据类型1> 变量名1(数据多少) vector <int> n(5); 用一个容器初始化另一个容器 voctor<数据类型1>变量名2(变量名1):vector <int> n(m); 这种情况不能够初始化vector
增添元素:变量名1.push_back(所添加的函数)
1. vector二维数组的初始化:vector<vector<int>> ans(r, vector<int>(c)); 定义的是行为r,列为c的二维数组
- 数组中,如果想用新的变量去接收vector中的数的话,那么用vector.front()接收第一个,而不能用vector.begin(),array也一样
- 数组容器的定义
array <type,arraySize> arrayName
二维数组的定义:array<array<int,cloumns>,rows> b,数组容器的二维数组定义就直接按顺序写,不能如42一样操作
1. 数组的定义中array(int,size),size一定要是一个常量
- 基于数组容器的for语句: for(int item:items) 用item遍历items里面的所有元素,item的数据类型必须跟items的一致(range-based for statement)
- 多维数组的赋值:a[b][c]={{1,2,3},{d,e,f},{4,5,6}}:表示b行c列,每个大括号表示一行,c不能省略,必须给出,然后中间的{d,e,f}不能为空,定义空行必须填0
- 内置数组:我们熟悉的数组, 初始化时大小的定义可以省略: int arrray[]={1,2,3,4,5,6,7} 内置数组的begin(array)和end(array)在头文件:里面,
- 数组名.size()可以获取数组的大小 变量名1.size()返回容器大小,内置数组不行
- static数组,如果没有初始化,那么编译器会自动初始化为0,数组也可以是静态的
指针与引用
- 引用:引用必须初始化,不可修改引用指向的地址(比如int &b=a,那么就不能改为&b=c了,当然,可以b=c,因为这是赋值操作)
- 指针初始化:
int * ptr;
- 取址符&: y=&y1 y是指针
- 输出时,输出y是输出地址,输出*y输出对应地址的值
- C++中,所有参数其实都是按值传递的
-
- 常量指针(constant pointer):const修饰指针:可以修改指针的指向(即使指向的值变化了),不可修改值,但只是不能通过这个指针修改值,而通过别的方式修改变量的值之后,指针输出的值也会跟着修改
const int *p=&a;- 指针常量(pointer constant)不可以修改指针的指向,可修改值,必须在定义行就初始化
int * const p=&a;- 既修饰常量,又修饰指针: 不可以修改指针的指向,不可修改值
const int * const p=a; - The name of an array is a constant pointer:数组的名称是一个常量指针,也就是可以修改指向,不能修改值
- 对于将数据赋值给指针,如果没有申明数组第几位,那么默认是第一位
- 指针的赋值:变量名(不带*)=&变量名
*indirection operator :解引用操作符, 空指针不能被解引用- 获取内置数组长度的方式:
sizeof(),sizeof(数组变量名)/sizeof(数组变量名[0])
- 指针与数组:int p, int arr[5] p=arr(这个地方不用加取址符)等价于p=&arr[0], 也就是指针获取了数组的首地址,指针的变量名等价于数组的名称(前面不用再加号)
- 如果指针指向内置数组,那么指针可以进行加减运算
- 用空指针赋值给对应的变量: 任意的指针之间是可以随意互相赋值的,包括空指针
int* sPtr=nullptr(定义空指针)
int number=*static_cast<int *>(sPtr;)
- 指针字符串:
- 初始化:
char color[]="absdfbsdf" const char *colorprt="absdufua" char color[]={'b','u','l','e','\0'} (理论上来说必须要加'\0'),必须是单引号,char数组结尾默认是加'\0'的,所 以在定义的时候char a[e]="bcd" e==4而不是3 用指针接收char数组名,比如char *p=color, 那么cout<<p<<endl; 的结果就是打印color字符串 - unique_ptr
- 能够自动管理任意类型的资源(比如说动态内存)
- 超出定义域之后,自动调用delete
Technics
- 头文件:不能用using,要用std::域作用符,避免namespace命名空间混乱
- include: C++自己的库只能用"",但是官方的库可以用<>或者""
- C++ 截取字符串函数(在 中)substr(start,end),截取后为[start,end],返回截取后的值
- end:str.size()获取长度
- C++中else与最近的if语句关联
- unsigned int: 无符号整数,用于存储非负整数,存储的范围是0~4,294,967,295
- 显式强制转换数据类型: static_cast(变量名) 变量名一定要加括号啊
- C++赋值语句:1)数据类型 变量名=值 2)数据类型 变量名={值} 3)数据类型 变量名{值}
- ++操作可以在任意的语句中进行 a=0 cout<<a++<<endl; cout<<a<<endl; >>>0 >>>1
- ++i是运算语句,所以无论在哪里,++i都是有效的(包括在if等语句中), i++也是如此 ++i返回的是i自增后的地址, i++返回的是i自增前的值
- 乘方函数:pow(x,y) #include 输出x的y次方 x,y均是double类型的数据 cmath库自动把x,y转换成double
- switch语句格式:switch(variable(integer only))其中对应的整数不能在case中重复使用
case 1:
skjdflksjd
break;
default:
sdkfsd;
break;
- 字符使用要用单引号,字符保存的是askcell码值
- 在条件判断中使用赋值语句,如果赋值不是0,那么全为真 if(a=1)->真 if(a=0)->假
- \x16进制字符
- cmath库 几个好用的函数:fmod(x,y):浮点数取模,fabs(x):取绝对值 sqrt(x):开平方根,x不能为负数
- register寄存器变量是单个变量,加快访问速度(没有地址)
- enum variable{VARIABLE1, VARIABLE2, VARIABLE3.....}枚举算法:是一些传递整数值的常量(实际是变量,但初始化后不能改),用于赋值,variable variables=VARIABLE1
- 初始化:默认是从0开始递增,当然也可以自己初始化,不同的VARIABLEA可以有相同的值 enum是域作用的,也就是说可以定义与已经定义的字符名相同的变量,加上variable:VARIABLE1就可以了
- 或者可以用 enum class variable{}
- static 在函数的最初阶段就创造内存空间,并且会随着程序变化而变化,它的作用域在定义它的函数里面
- 堆栈:后进先出
- 一元作用域分辨运算符(scope resolution operator) ::访问的是全局变量,访问静态成员等等
- binary_search():二分查找 在algorithm库里面,语法是: bool found=binary_search(数组的起始查找位置,数组的终止查找位置,查找目标)
- debug
# include<stdexcept>
try:
{
执行的操作
catch(报错类型、名称)
{
cerr<<jfksjldfk<<ex.what()<<endl;}
}
throw 报错类型(输出) 会立即返回,有点类似return
#比如
throw invalid_argument("sth. is out of range" );
- 编译原理
- editor: creats program and stores it on disk
- preprocessor: preprocessor program processes the code
- complier: creats object code and stores it on disk
- linker: links the object code with libraries, creat an executable file and stores it on disk
- loder: puts program in memory
- CPU: takes each instruction and executes it, storing new data values
- C++中不用大括号: if...else 中if不用大括号的话只能有一行语句,多则else无法识别 else 识别的是离他最近的if语句
- 占空间:指针:64位8个字节 32位4个字节(byte)Int:4个字节 float:4个字节 double: 8bytes char: 1byte long long: 8bytes bool: 1byte short: 2bytes string: 8byte
- C++支持连续比较大小(x<y<z)
- source code:源文件 .cpp
- C++浮点除法的处理:整数/整数的话,就要1.0/2,这样返回的就是浮点数
- \t:水平的tab \0: string的结束符, 必须要有,不然容易报错
- 注意所有计数器、记录累加、累乘结果的变量都必须先初始化,再操作
- 空白语句:只有一个分号的语句
- 可以找到对应的数据类型的上限和下限:INT_MAX, INT_MIN 在库中:include unsigned int 的最大值:UINT_MAX
- do while语句
do{
statement
}
while(); 其中do的大括号可以省略
- &&的优先级比||高
- 编码:bit<character(byte)<field<record<file
- 换行输出要在两行之间打<< escape character:\
- 取模和乘法的优先级相同
- +=,-=,*=,/=都是先算等号右边的结果然后再与左边的变量进行加减乘除运算
- const字符定义的变量都必须初始化(除了常量指针)
- for循环后如果不加括号,那么只能照顾到第一个语句()比如if语句,或其他,接下来就直接跳出for循环了
- for循环中的边界条件如果有多个并列的,要用&&连接起来
- 浮点数、整数之间理论上是可以互相赋值、转化的,但是要注意数据的准确性
- ACSLL码值:0——48,a——97,A——65, 字符和整数的相互转化,就用static_cast<int/char> (a)
- 使用typedef进行重命名:只能把已有的对象进行重命名
typedef int INT INT a=1; - 使用const_cast强制将const或者volatile类型的限定去除
const char *mutablee='1';
char *mu=const_cast<char *>(mutablee);
mu='2';
- namespace
- using namespace std: 将std的namespace都用在这里
- 如果命名空间在相同的函数中用不同的命名空间的值,那么global的就是::variable
namesapce name{ int a=3; int b; namespace inner{ int c=1; } void test(); } namespace{ // unnamed namespace int a=5; int b; } int main(){ cout<<a; //输出5,from blank namespace cout<<name::a<<endl; //输出3 cout<<name::inner::c; //namesapce可以嵌套 } void name::test{ cout<<a<<inner::c<<endl; }- 还可以给namespace起别名
namespace CPPHTP = CPlusPlusHowToProgram; - 位运算用英文单词表示:&& and || or ! not
运算符重载
- new的是创建数据的地址,用指针接收
- new的本质:调用对应对象的构造函数
double * p= new double (10)
int * arr= new int [10]() (默认的初始化为0/flase/nullptr)
int *arr=new int[10]{}// C++11
Time *timeptr= new Time(12,45,0);
- 手动删除堆区的数据用delete:
delete p;
delete[] arr;
- 空类的内存大小为:1
- 左值: 能够修改 右值:返回的是对象的值,不能够修改
- ptr初始化 ptr(new int[size])
- 没有加句柄的默认是类的成员
- 常量成员函数不能调用非常量成员函数,反之可以
- 动态内存管理,要自己写copy constructor: 用于pass by value, 能够初始化,隔离内存,确保不在同一个内存
- 如果写一个自定义的数组类,记得写copy constructor, destructor , overloaded assignment operator
- Array (const Array&)=delete; 删除默认构造函数, 将运行错误转化为编译错误
- conversion constructor: 类型转换,(可能隐式调用:将整型转换为浮点型)
- 类型转换:静态类型转化: static_cast<char *> (s) 转换为字符指针
- 不能重载的运算符:. .*(pointer to member) :: ?;
- 尽量不要重载的运算符:& && ||
- 重载() [] ->的时候,重载函数一定要声明为类的成员函数,其他没有强制要求
- 重载类型
- 重载输入输出运算符
class a{ friend std::istream &operator>>(std::istream &, a &); friend std::ostream &operator<<(std::ostream &, const a &); private: bool output=false; }; std::ostream &operator<<(std::ostream &output, const a &A){ output<<"Output"<<A.output; return output; //这里return output是为了让<<运算符可以连续调用 } std::istream &input &operator>>(std::istream &input, a &A){ input>>A.output; return input; }- 重载关系运算符: >,<, ==, >=, <=, 必须成对重载
bool operator==(const classname & name) const ;// 返回布尔值,然后参数都是const 引用,作为成员函数重载 bool operator<(const String &, const String &) //2. 作为非成员函数- 重载赋值运算符
const Array & operator=(const Array & a){ //这个const防止(a=b)=z的情况发生 if(&a!=this) { //第一步判断对应的地址是否相同 //第二部赋值,对应的赋值操作自己想 } }- 重载前置和后置递增/递减运算符
Date & operator++(); //类内的前置自增运算符 Date & operator++(Date &); //类外的前置自增运算符 Date operator++(int) //类内的后置自增运算符, int用于区分前后置 Date operator++(Date &, int);//类外的后置自增运算符- 重载下标访问运算符:subscript operator
int & operator[](int subscirpt); //支持连续调用 const int & operator[](int subscript) const;// 这里使用const int&, 这个const是防止由于返回引用导致修改对应的值,用于const对象的查询- 重载函数调用运算符:
String String::operator()(size_min index, size_max length) const- 重载加号运算符 重载!运算符
bool operator!() const{return !this->a}; bool operator!(const String &){}; // non-memeber function Class & operator+(class c){ return } - 重载== !=: 其实只需要写一个重载的逻辑代码,另外一个调用这个重载的代码就可以了
- explicit 显示构造函数,防止发生隐式类型转换
- 无法隐式重载“+=”
文件读写
-
流程:
- 文件读取
- 文件读取类名: fstream,ofstream,ifstream
- 然后包含对应的文件名,
- 读写方式(ios::in|ios::out|ios::binary|ios::ate),注意使用ostream只能out,使用istream只能in
- out: 顺序存储,删除掉之前的文件内容,重新从头开始写入
- in: 顺序读取
- app: 从上次文件结尾处开始写入
- binary: 二进制(随机)文件读写
- sequential file:
ofstream outClientFile("name.txt",ios::out) //ios::out会自动擦除原来的文件,并且从头开始输入, ios::app会从上次文件的结尾处开始添加所以的输出数据 ofstream outClientFile; outClientFile.open("name.txt",ios::out)- ramdom file:
ifstream inCredit("credit.dat", ios::in| ios::binary);
- 检查读取是否成功
# include <cstdlib> if(!outClientFile){ cerr<<"Fail to open the file"<<endl; exit(EXIT_FAILURE); //相当于return 0 }- 对应的文件操作, 非常关键的步骤是在写入文件之后要seekg()和clear(),不然文件无法顺利读取
- 顺序文件读写
//文件写入 while(cin>>account>>name>>balance){ outClientFile<<account<<' '<<name<<' '<<balance<<endl; } outClientFile.clear() //清空文件的状态 outClientFile.seekg(0) //从头开始读 //文件读取 while(inClientFile>>account>>name>>balance){ outputline(account,name,balance);// 封装好的函数 }- 随机文件读写:方式:首先要创建类,类中使用char数组存储字符串
file.write(reinterpret_cast<const char*>(&pointer),sizeof(pointer)) file.read(reinterpret_cast<char*>(&pointer),长度) - 文件关闭: main函数结束会自动隐式调用析构函数,也可以显示调用
outClientFile.close() -
即使没有对应的文件名,ios::out也会创建一个对应的文件名,但如果是ios::out和ios::in的组合,则不会自动创建
-
ios::out是ofstream的默认格式
-
seekp与seekg: 文件写/读的光标对应的指针
- seekp: "seek put" 在ofstream当中,重定位写入文件的光标
- seekg: "seek get" 在ifstream当中,重定位读取文件的光标
- 相对应的,还有tellp()和tellg(),返回当前光标位置的long型的值
// 定位到 fileObject 的第 n 个字节(假设是 ios::beg) fileObject.seekg( n ); // 把文件的读指针从 fileObject 当前位置向后移 n 个字节 fileObject.seekg( n, ios::cur ); // 把文件的读指针从 fileObject 末尾往回移 n 个字节 fileObject.seekg( n, ios::end );
- 二进制文件用于读写结构化的内容,比如对应的类,或者对应的结构体
- EOF——end of file 返回值为-1,是个常量 //TODO::再查清楚一点
- 二进制文件删除对象的方法:用一个空对象进行替换
- 检查文件结尾:使用void *, 如果遇到了文件EOF,failbit,badbit, 那么void * 都会变为false,就直接return, 不再进行读写
类模板
- 栈:stack 先进后出,后进先出
- Class templates are called parameterized types, because they require one or more type parameters to specify how to customize a generic class template to form a class-template specialization.
- 格式
template< typename T >
class stack{
public:
void push(const T &pushvalue) //用于替代位置的数据类型
private:
deque<T> name;
};
//类外定义成员函数
template< typename T >
inline void Stack<T>::pop()
{
stack.pop_front();
} // end function template pop
//单独定义函数
template<typename T>
void func(const T& value1, const T& value2){}
//nontype template parameters
template < class T, size_t N >
class array{};
- 作用:类模板提供了在类型不确定情况下对于某个数据结构进行操作,给出统一的指令,也就是说类模板是一个泛型
- 实例化方式
stack<double> name;
array<double,1000> name;
func(1.1,1);
func(2,1.1);
- 模板不允许在main里面声明