C++查缺补漏
基础语法:
运算符
- 优先级:https://blog.csdn.net/nicky_zs/article/details/4053146
- 优先级1:作用域,对象中访问成员,后置自增自减,括号
- 优先级2:单目(!逻辑非/~按位反/-负/+正),指针,枪支自增自减,(type),sizeof字节长度
- 优先级3:对象中通过指针访问成员
- 优先级4,5:乘除余,加减
- 优先级6:按位左移(右补0)右移(有符号补符号,无符号补0)
- 优先级7,8:比较运算符,等于/不等于
- 优先级9,10,11:按位与,按位异或,按位或
- 优先级12,13:逻辑与,逻辑或
- 优先级14,15,16:三元条件操作符,赋值/复合赋值操作符,逗号操作符
- 结合性:优先级2,14,15为从右至左,其余皆是从左至右
变量初始化问题:https://www.cnblogs.com/FoxShark/p/5802239.html
- 内置类型变量:取决于变量定义位置,函数体外初始化为0,函数内未定义
- 类类型变量:
- 自动生成的默认构造函数使用与变量初始化相同的规则来初始化数据成员
- 若定义一个构造函数以阻止编译器自动生成默认构造函数,报错
- 类内成员变量一般有如下四种:
- 一般变量(int):可以在初始化列表里或者构造函数里初始化,不能直接初始化或者类外初始化
- 静态成员变量(static int):必须在类外初始化
- 常量(const int ):常量必须在初始化列表里初始化,不可以使用赋值
- 静态常量(static const int):静态常量必须只能在定义的时候直接初始化
指针与引用
- 本质:指针将内存地址作为变量值,引用是通过指针来引用变量的值。
- 初始化:指针被初始化为0/NULL/一个地址(拒绝野指针!!!),引用在声明时必须进行初始化。
- 三种传递参数方式:https://blog.csdn.net/u013130743/article/details/80806179
- 传值
- 传指针:本质上仍是值传递(传变量)的方式,它所传递的是一个地址的副本,是可以循迹于本体但独立于本体的,可空,无类型检查。
- 传引用:就是本体,传递的是它的别名而已,紧密依赖于本体且从一而终,非空,有类型检查。
C++类型转换
- 四种显式转换http://c.biancheng.net/cpp/biancheng/view/3297.html
- 隐式转换
类
- 继承:
- 支持多继承:class C: public A, public B
- 权限:
- 私有成员不可直接被继承的类访问;公开和保护的按选择的继承方式被继承;
- 基类成员在派生类中的访问权限不得高于继承方式中指定的权限。
- 友元函数不可被继承
- 基类构造函数,析构函数,重载的赋值运算符不能被派生类继承
- 重名函数构成覆盖,只有同一作用域下才构成重载
- 虚继承:
- 菱形继承带来的二义性问题:
- 如果 B 和 C 中都没有 x 的定义,那么 x 将被解析为 A 的成员,此时不存在二义性。
- 如果 B 或 C 其中的一个类定义了 x,也不会有二义性,派生类的 x 比虚基类的 x 优先级更高。
- 如果 B 和 C 中都定义了 x,那么直接访问 x 将产生二义性问题。
- 虚派生只影响从指定了虚基类的派生类中进一步派生出来的类,它不会影响派生类本身。不论虚基类在继承体系中出现了多少次,在派生类中都只包含一份虚基类的成员。
- 菱形继承带来的二义性问题:
- 派生类的构造函数,一定是先自动调用父类的构造函数。、
- 要是为父类的构造函数提供了参数
B(int mm,int nn):A(mm)
。在A(mm)
时,也就是显示的调用了父类中的非默认构造函数,所以必须传参!!! - 如果程序员没有显示调用,则B中自动有一个A的默认构造函数。
- 要是为父类的构造函数提供了参数
- 多态:
- RTTI(Run Time Type Identification)即通过运行时类型识别,程序能够使用基类的指针或引用来检查着这些指针或引用所指的对象的实际派生类型
- 虚函数:
- 必须使用虚函数才能完成多态!!!否则C++中静态编译,会自己使用指针类型(基类)的方法和派生类的成员变量,这时候是隐藏,同名函数会互相隐藏彼此的方法。
- 虚拟函数:静态绑定,当使用对象通过点运算符访问虚拟函数,函数调用将在编译阶段被解析 vs 动态绑定,动态绑定出现在使用指针或引用作为句柄时
- 纯虚函数:
virtual void draw() const = 0;
必须重写。抽象类必须至少有一个纯虚拟函数。 - 可以使用 dynamic_cast 将派生类指针赋值给基类指针,下行转换更安全
- 虚析构函数:如果一个类有虚拟函数,该类就需要提供一个虚析构函数,尽管该析构函数并不一定是该类需要的,因为我们需要调用派生类的析构函数。构造函数不能是虚拟函数,声明一个构造函数为虚拟函数是一个语法错误。,看虚析构函数的作用和原因:http://c.biancheng.net/view/269.html
- 方法(和java的快混了,java中普通函数就是c++中虚函数,所以:https://www.runoob.com/java/java-polymorphism.html & java中隐藏只有一种方式:https://blog.csdn.net/snow_7/article/details/51579278):
- 重载:是指不同的函数使用相同的函数名,但是函数的参数个数或类型不同。调用的时候根据函数的参数来区别不同的函数。
- 覆盖:(也叫重写)是指在派生类中重新对基类中的虚函数(注意是虚函数)重新实现。即函数名和参数都一样,只是函数的实现体不一样。
- 隐藏:是指派生类中的函数把基类中**相同名字(不管参数和返回值)**的函数屏蔽掉了,需要类::才能调用。
- 组合:类中类就是组合!!!
- 类模板:
template< typename T1, typename T2 >
构造函数
- 默认/缺省构造函数,即构造时,不需要传递参数的(**???**c语言中文网的没看懂啊)
- 无参的:不论是编译器自动生成的,还是程序员写的,不管有没有在初始化列表中或在{}中为参数赋值,都称为默认构造函数,没有赋值的会给一个随便的值???。如果编写了构造函数,那么编译器就不会自动生成无参的默认构造闲数。
- 不使用
new+无参
的构造函数,后面不要加括号,此时自动调用构造函数,使用完自动收回。此时对象在栈中,对象名只是一个名称,对应了某个内存位置,不占空间。否则(加括号的情况),不调用任何构造函数创建对象,其实是声明了一个函数而已!!! - 使用new,后面必须加括号,除非是调用没有参数的构造函数也可以省略括号,还要必须自己销毁空间!C++中new就相当于C中的malloc,分配一块空间,返回指针。
- 不使用
- 有参的:所有参数都拥有默认值,就是只要我不写还能匹配的函数此时被默认构造函数。不关心成员变量有没有被初始化。
- 初始化方法1:声明中指定默认参数+定义中{}内传值。
- 初始化方法2:初始化列表中赋值。
- 无参的:不论是编译器自动生成的,还是程序员写的,不管有没有在初始化列表中或在{}中为参数赋值,都称为默认构造函数,没有赋值的会给一个随便的值???。如果编写了构造函数,那么编译器就不会自动生成无参的默认构造闲数。
- 拷贝构造函数:
- 编译器也自动提供一个默认拷贝构造函数,其作用是使用传入对象的值生成一个新的对象的实例,从而产生了新的对象! vs 赋值运算符时将对象的值复制给一个已经存在的实例
- 默认格式
类名(const 类名&变量名)
:- 加不加 const 对本程序來说都一样。但加上 const 是更好的做法,这样复制构造函数才能接受常量对象作为参数,即才能以常量对象作为参数去初始化别的对象。
- 必须以引用的方式传递参数。这是因为,在值传递的方式传递给一个函数的时候,会调用拷贝构造函数生成函数的实参。如果拷贝构造函数的参数仍然是以值的方式,就会无限循环的调用下去,直到函数的栈溢出。
- 何时候被调用:
- 用一个对象初始化同类的另一个对象:
Complex c2(c1); // 初始化 Complex c2 = c1; // 初始化 Complex c1,c2; c1=c2; // 不是初始化,而是赋值,赋值不会引发复制构造函数的调用
- 对象作为函数的参数时:调用所给的实参去初始化作为形参的对象!
- 对象作为函数的返回值时:调用拷贝构造函数
- 关于深拷贝与浅拷贝:https://blog.csdn.net/qq_29344757/article/details/76037255
- 构造函数规则:
- 一个类仅允许零个/一个默认构造函数,用于省略式定义对象,也就是说以上两种不允许同时出现
- 如果类的设计者没有写任何构造函数,那么编译器才会自动生成一个没有参数的构造函数,虽然该无参构造函数什么都不做。
- 初学者常因“构造函数”这个名称而认为构造函数负责为对象分配内存空间,其实并非如此。构造函数执行时,对象内存空间已经分配好了,构造函数作用是初始化这片空间。但常常用于分配动态空间,如指针需要指向某处等。
- 构造函数和析构函数都没有返回值,是没有,而不是void
- 构造函数的执行阶段:
- 首先是成员对象在宿主对象构造之前进行构造,且是按照它们在类定义中出现的顺序进行构造,而不是按照在初始化列表中出现的顺序
- 初始化阶段,随着构造体函数一开始执行,初始化就完成了。初始化列表是构造函数的一部分,格式
构造函数:成员变量(值),成员变量(值)
,对于基本类型相当于在{}赋值(vs 函数缺省值,函数只是在没给实参时拿默认的参数赋予形参了,在{}中不传给成员变量还是白搭),但以下三种类型必须使用初始化列表,只能括号,不能赋值:- 常量成员,因为常量只能初始化不能赋值,所以必须放在初始化列表里面
- 引用类型,引用必须在定义的时候初始化,并且不能重新赋值,所以也要写在初始化列表里面
- 没有默认构造函数的类类型,因为使用初始化列表可以不必调用默认构造函数来初始化,而是直接调用拷贝构造函数初始化。
class Test1 { public: Test1(int a) : i(a) {} int i; }; /* // 这样是不可以的,Test1 test1只是一个声明,并无实体,后面赋值的时候(C++中赋值,默认为浅拷贝!),没有被构造,那就会自己调用默认的构造函数!但是Test1没有默认构造函数555 class Test2 { public: Test1 test1; Test2(Test1 &t1) { test1 = t1; } }; */ // 这样是可以的,Test1 *test1只是一个指针,并无实体 class Test2 { public: Test1 *test1; Test2(Test1 &t1) { test1 = &t1; } }; int main(void) { Test1 t(2); Test2 test2(t); }
- 普通的计算阶段,即可以是那些赋值语句之类的。不管成员是否在构造函数初始化列表中显示初始化,类类型的成员总是在初始化阶段初始化。
- 编译器默认生成的六个方法,程序员可以在声明后使用
=delete
指定不生成。
class Empty
{
public:
Empty(); // 默认构造方法
Empty(const Empty &); // 拷贝构造函数
~Empty(); // 析构函数
Empty &operator=(const Empty &); // 赋值构造函数
Empty *operator &(); // 取地址
const Empty * operator&() const; // 常对象取地址
};
动态分配空间
- 内存的分配与释放:
// `malloc`和`free` int *p; p = (int *)malloc(sizeof(int) * 10); free(p); // `new` 和 `delete` int* p; p=new int; delete(p); // 有没有括号是一样的 int* p; p=new int[n]; delete [] p;
- 测试动态数组:
int* a,b[5],i; a=new int[5]; cout<<"a="<<a<<endl; cout<<"&a="<<&a<<endl; cout<<"&a[0]="<<&a[0]<<endl; cout<<"&a[1]="<<&a[1]<<endl; cout<<"=============="<<endl; cout<<"b="<<b<<endl; cout<<"&b="<<&b<<endl; cout<<"&b[0]="<<&b[0]<<endl; cout<<"&b[1]="<<&b[1]<<endl; /* a=0x1031688 &a = 0x60fe88 栈上 &a[0] = 0x1031688 &a[1] = 0x103168c == == == == == == == b = 0x60fe74 栈上 &b = 0x60fe74 栈上 &b[0] = 0x60fe74 栈上 &b[1] = 0x60fe78 栈上 */
函数
- 几个定义:
- 函数原型:名称,返回类型,参数
- 函数签名:名称,参数
- 允许类型的自动转换(提升)
- 友元函数:
- 定义在类外部,但有权访问类的所有私有(private)成员和保护(protected)成员。
- 格式:
return_type operator?(param_type param1, ...)
- 友元函数的原型有在类的定义中出现过,也可以直接把整个友元函数定义在类中,但是友元函数并不是成员函数。只是可以访问,而不是直接拿来用(隐含的this指针)。
- 友元函数没有this指针,则参数要有三种情况:
- 要访问非static成员/函数时,需要对象做参数。
- 要访问static成员/全局变量时,则不需要对象做参数。
- 如果做参数的对象是全局对象,则不需要对象做参数。可以直接调用友元函数,不需要通过对象或指针。
- 两点注意:
- 友元关系不是对称的,并且不能传递
- 友元需要被授予,而不是索取。授予某个函数/某个类(所有成员函数都可以访问我的变量和函数!)作为自己的友元,即允许他们访问啦。
- 类型转换函数:
- 类中成员函数,必须为非静态成员函数。无需声明返回类型,因其会隐式地返回转换后的类型
- 格式:
operator 类型名( ){// 实现转换的语句}
- 类型转换后无需再重载一些运算符了
- 例,将类 A 转换为临时的 char *:
static_cast< char * >( s )
就是调用: s.operator char *(){…}
存储权限
- auto:局部变量,函数的默认存储
- register:不在内存中分配,高速读写,无法被&操作
- extern
- mutable:在类成员中使用,修饰一个类成员变量时,即使类成员函数定义为const,也可以在该成员函数中修改被mutable修饰的成员变量
- static:
- 修饰局部变量时,该局部变量将放在静态存储区存储,生命周期为程序的生命周期。但并不意味着这些标识符在整个程序中都能使用。
- 修饰全局变量时,该变量只在本声明文件中可见。
- 修饰类成员时,对象不存在时就已存在,默认初始化为0,该类成员将独立于类对象,由所有类对象共享。如果是const,可以在类定义中声明时初始化;其它的则必须在文件作用域内(类定义外)定义,因为其独立于类对象,像属性,随对象的定义而定义。static 成员变量属于类,不属于某个具体的对象,即使创建多个对象,也只为其分配一份内存,所有对象使用的都是这份内存中的数据。当某个对象修改了,也会影响到其他对象。
- 修饰类成员函数:类的非静态类成员函数内含了一个指向类对象的指针型参数(即this指针),因而只有类对象才能调用(此时this指针有实值),而静态函数没有this可以被类调用
- 补充好好看看:
- static和const:https://www.runoob.com/w3cnote/cpp-static-const.html
- 类数据成员:https://www.cnblogs.com/silentjesse/archive/2013/07/27/3219193.html
- 变量的定义和声明:http://c.biancheng.net/cpp/biancheng/view/143.html
- 关于重定义问题:https://blog.csdn.net/Amos_zh/article/details/104907054
文件
- 小runnoob入门:https://www.runoob.com/cplusplus/cpp-files-streams.html
- 更详细的:
- https://www.cnblogs.com/azraelly/archive/2012/04/14/2446914.html
- c语言中文网:http://c.biancheng.net/cplus/60/
- 你需要注意的是cin,cout,cerr和文件是同一类对象,以及它们之间的继承关系。只不过前者是标准输入输出,后者是自己通过方法或构造函数指定的。
运算符重载
- 概述:
- 重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的。与其他函数一样,重载运算符有一个返回类型和一个参数列表。
- 运算符必须被显式重载,如:(“+”)是不可以自动重载相关的运算符的(如:“+=”)
- 可以把一个运算符作为一个非成员、非友元函数重载。但是,使用set,get调用这些函数所涉及的开销会降低性能。可以将这些函数内联以提高性能。
- 三种重载:刘东明老师的书这一节还是值得一看滴!
- 输入输出:https://blog.csdn.net/lyh__521/article/details/49601489
friend istream& operator>>(istream& os,A& a) { a.input(); return os; } friend ostream& operator<<(ostream& os,A a) { a.output(); return os; }
- 双目
- 单目
A operator++() //++i { ++m; return *this; } A operator++(int t) //i++ { A old(*this); ++(*this); //m++ return old; }
- 输入输出:https://blog.csdn.net/lyh__521/article/details/49601489
this
- this指代对象,但并不是对象的一部分 ,每个函数其实都会传,是编译器帮我们完成的啊
- 成员函数知道在处理哪个对象的数据成员,因为this被编译器作为隐式参数传递给对象的非静态成员函数
- 当直接访问数据成员时就是隐式使用了this
- 通过
return *this
可以完成计量函数的调用
异常
- 堆栈展开(Stack unwinding):如果没有发现匹配的 catch 处理程序时发生,程序试图在调用函数中定位其他的 try 语句块
- 重新抛出异常:空 throw; 语句
- 异常说明:关键字 throw,逗号分隔的参数。例:int someFunction( double value )throw ( ExceptionA, ExceptionB,ExceptionC ){…}。没有异常说明表示这个函数可以抛出任意异常,空异常说明 throw(),表示该函数不能抛出任何异常
- 当函数抛出其异常说明外的异常时调用通过 set_unexpected 注册的函数(?),该函数可以调用 terminate 或者 cstdlib::exit 或者 cstdlib::abort 中止程序的执行。也可以把异常再次抛出,或者抛出别的异常。terminate:调用通过 set_terminate 注册的函数 & 默认的调用 abort 函数。
- 构造函数抛出的异常使得任何已经构造好的对象组件调用它们的析构函数
库函数
-
产生随机数:
srand(time( 0 ))
和rand()
-
vector<type>
:- 缺省的所有 vector 中的元素被初始化为 0
- 成员函数 size 得到数组的长度
- vector 对象之间可以进行比较和其他逻辑运算,甚至可以赋值!
- vector 的成员函数 at,相比数组,多了边界检查
- 常用方法:
push_back()
:在Vector最后添加一个元素(参数为要插入的值)erase()
:删除指定元素 (可以用指针来代替迭代器)begin()
:b用于返回指向向量容器的第一个元素的迭代器。end()
亦然。size()
:返回元素个数find()
:http://c.biancheng.net/view/570.htmlfind_if()
:https://blog.csdn.net/zhy10/article/details/1557685?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-2.control&dist_request_id=&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-2.control- 函数指针:https://baike.baidu.com/item/%E5%87%BD%E6%95%B0%E6%8C%87%E9%92%88
- 函数对象:http://c.biancheng.net/view/354.html
- demo:
static bool cmp(int n1,int n2) { return n1>n2; } void sort1_2() { sort(a1,a1+n,cmp); }
for_each()
:
-
map<type,type>
:insert()
:http://c.biancheng.net/view/7181.html
-
typeid运算符:返回type_info类对象的引用,对象信息
-
Exception类中的what,返回异常存储错误信息
-
windows.h
-
typeid
:运算符而非函数,输出类型,根据编译器的不同而不同 -
String
:- 属性:
- size_type: unsigned类型,可以保证足够大可存储任意string对象的长度
- npos:找不到
- 长度:
size()
,length()
:返回string中字符个数,即已使用的capacity()
:不重新分配的情况下,能存多少字符,当前内存支持多少max_size()
:最多可以支持的字符数
- 关于子串:
s.find(string ,pos)
:从pos开始查找string,找到时返回size_type,找不到返回nposs.rfind(string,pos)
:向前找,即从右侧开始查找substr(pos1,pos2)
:取子串
- 判断:
isdigit(char)
,isalpha(char)
,isupper(char)
,islower(char)
,isalnum(char)
- 转化:
reverse(s)
stringstream ss<<string s
+stringstream ss>>int num
toupper(char)
,tolower(char)
- 属性:
-
clock_t t
:clock()
:取得当前时间
-
输入:
int getchar(void)
:从键盘读取一个字符并输出,该函数的返回值是输入第一个字符的ASCII码;若用户输入的是一连串字符,函数直到用户输入回车时结束,输入的字符连同回车一起存入键盘缓冲区。若程序中有后继的getchar();函数,则直接从缓冲区逐个读取已输入的字符并输出,直到缓冲区为空时才重新读取用户的键盘输入。相当于getc(stdin)
。返回类型为int型,为用户输入的ASCII码或EOF。头文件<stdio.h>int getch(void)
:用于从stdio流中读字符,即从控制台读取一个字符,且该函数的输入不会自动显示在屏幕上,需要putchar()
。不用按回车就返回,但不显示在屏幕上;语法为:“int getch(void)”,返回读取的字符ASCII码。头文件<conio.h>char *gets(char *string)
:从stdin读字符串直到enter,会读走enter,但不放在字符串中,并自动为字符串添加\0。从流中读取字符串,直到出现换行符或读到文件尾为止,最后加上NULL作为字符串结束。所读取的字符串暂存在给定的参数string中。由于gets()不检查字符串string的大小,必须遇到换行符或文件结尾才会结束输入,因此容易造成缓存溢出的安全性问题,导致程序崩溃,可以使用fgets()代替。int getc(FILE *stream)
istream& getline ( istream &is , string &str , char delim );
int kbhit(void)
:检查当前是否有键盘输入,若有则返回一个非0值,否则返回0。
UML表示方式:https://www.w3cschool.cn/uml_tutorial/uml_tutorial-c1gf28pd.html
- 类:
- 加粗类名
- 符号:-私有,+公有
- 变量名:类型
- 构造方法:
<<constructor>> + 类名(参数)
- 方法:返回值类型
内存管理:https://zhuanlan.zhihu.com/p/51855842
全局/静态存储区域
- 内存在编译期间就已经分配好,这块内存在整个运行期间都存在
- 例如全局变量,静态数据,常量
代码区:所有类成员函数和非成员函数代码存放在代码区
栈区
- 为运行函数而分配的局部变量、函数参数、返回数据、返回地址、引用类型等存放在栈。
- 自动分配与回收,效率高,但是分配的内存量有限.在不使用new创建对象时,对象的内存空间是在栈中的,其作用范围只是在函数内部,函数执行完成后就会自动调用析构函数,删除该对象。
堆区
- 由程序员控制,malloc、new,free、delete。使用 new int 或 new int[块内存大小] 创建对象是创建在堆中的,必须要程序员手动的去管理该对象的内存空间,要检查一下有没有分配成功。只有使用new才在堆区分内存,只有使用delete或delete[]才会触发析构函数,delete后注意置空指针,避免二次释放。
- 关于delete释放数组的一点:如果语句中没有包括 [],并且 Array 指向一个对象数组,则只有第一个对象的析构函数被调用
- SIZEOF(CLASS/OBJECT)对象只包含数据。对类名或该类的对象采用sizeof运算符时,只能得到类的数据的长度。编译器生成独立于所有类的对象的成员函数的副本(只有一份)。类的所有对象共享这个成员函数唯一副本。
补充
- C++没有内存垃圾回收机制
- C++中,可以非new方法创建对象!,此时对象在栈中,栈的大小有限制,对象名只是一个名称,对应了某个内存位置,不占空间。而new出来的在堆上,且必须使用指针,指针在占内存
Subtle Traps
- 类的公有成员函数返回一个该类私有数据成员的引用;
- 当数据成员包含指针指向动态分配的内存中会导致严重的问题(**?*)
- 默认的拷贝构造函数是按成员拷贝构造,这导致了两个不同的指针(如ptr1=ptr2)指向了相同的内存。拷贝指针,但释放空间只释放一次,所以建议使用引用。当类的对象包含指向动态分配的内存的指针时,如果不为其提供重载的赋值运算符和拷贝构造函数会造成逻辑错误。
- 拷贝构造函数应使用按引用传递接受参数,而不是按值传递。否则复制这一步,将会出现无限循环调用构造函数。
零散知识点
- SET:使用set进行数据有效性验证和设置
- IF:函数逻辑的两种控制方式:堆叠&嵌套(效率更高)
- CONST:
- 思想:最低权限原则。
- 区分:指针const,int *const myPtr = &x;变量const,const int *myPtr = &x;
- 成员函数:const 对象只能调用 const 成员函数,const 成员函数不能修改对象,格式:ReturnType FunctionName(param1,param2…) const{…}
- 可以对 const 成员函数进行非const 版本的重载。编译器将根据调用函数的对象:如果对象是const 的,则编译器使用 const 版本的重载函数;如果是非 const 的,则编译器使用非 const 版本的重载函数
- 函数名前加const,返回值;后加,不可以对类成员进行修改,只读权限。
- 成员变量:
- 用冒号 (😃 与参数列表相分隔,数据成员名后跟括号,括号内必须包含初始值
- 初始化在构造函数执行前执行
- 常量数据成员(const 对象和const变量)和引用数据成员要初始化,不能用赋值语句
- 函数名前加const,返回值;后加,不可以对类成员进行修改,只读权限。
- CONSTRUCTOR:调用没有参数的构造函数也可以省略括号
- INLINE:不论是否用inline声明(或默认为inline),成员函数的代码段都不占用对象的存储空间。用inline声明的作用是在调用该函数时,将函数的代码段复制插人到函数调用点,而若不用inline声明,在调用该函数时,流程转去函数代码段的入口地址,在执行完该函数代码段后,流程返回函数调用点。inline与成员函数是否占用对象的存储空间无关,它们不属于同一个问題,不应搞混。
- ARRAYS_INIT:假如不是用执行时的赋值语句来初始化数组,而是在编译时用一个数组初始化列表来初始化数组,程序执行速度会更快。
- ARRAYS:数组名本质上为 constant 指针。故尽管数组名是指向数组开头的指针,并且指针可在算术表达式中修改,但是数组名不可以在算术表达式中修改,因为数组名实际上是个常量指针
- AFFECT_SCOPE:成员函数中声明的变量仅拥有块作用域(本函数),但如果在成员函数中定义一个与类的数据成员同名的变量,在成员函数中可以通过作用域运算符(::)来访问被隐藏的数据成员!
- 浮点数的格式化:
- setprecision:声明显示的精度,缺省为6位
- fixed:定点小数
- showpoint:强制显示小数点
- exit 函数:迫使程序立即终止,而不执行自动对象的析构函数,通常用来在程序检测到错误时终止程序。但会做一些释放工作:释放静态的对象,缓存,关掉所有的I/O通道,然后终止程序。如果有函数通过atexit来注册,还会调用注册的函数。abort是不允许任何对象的析构函数被调用。
- 左值引用和右值引用:https://zhuanlan.zhihu.com/p/97128024
- explicit:使得不能通过转换构造函数进行隐式转换,如
explicit Array( int = 10 );
- “实现继承”放在高层,“接口继承”放在低层
- ++i返回加后的值,自身的引用;i++返回临时变量保存加之前的对象,对象本身,开销大
- c++对cin进行了简化,自动判断类型
- 如何产生随机字符串:
- 产生随机数->转char
- 将string和int连接:https://blog.csdn.net/baidu_38172402/article/details/82218200?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-0&spm=1001.2101.3001.4242。注意:直接使用+会导致指针偏移,从而输出的不完整,即使加的是char,查看自动类型转换,https://www.jianshu.com/p/ed149d717cbc