[C/C++] C++ Primer学习笔记

记录下自己掌握不清楚的概念和用法...

Day 1

endl:具有输出换行的效果,并刷新与设备相关联的缓冲区。
	注:在调试程序过程中插入的输出语句都应刷新输出流,否则可能会造成程序崩溃,将会导致程序出错位置的错误判断。
		
buffer(缓冲区):输出缓冲区通常必须显式刷新以强制输出缓冲区内容。默认情况下,读cin会刷新cout;当程序正常结束时,cout也被刷新。
		
cerr:默认情况下,输出cerr不缓冲。通常用于不是程序正常逻辑部分的错误信息或其他输出。

clog:默认情况下,写到clog时是带缓冲的。通常用于将程序执行信息写入到日志文件中。

>>, << :都返回其做操作数,从而连续读入或输出。

while(std::cin >> x):在遇到文件结束符时停止读入。
	注:Windows系统下--"Ctrl+z"		Unix系统下--"Ctrl+d"

在C++中,把负数赋给unsigned对象是完全合法的,其结果是该负数对该类型的取值个数求模后的值。

通用转义字符:
	\ooo:ooo表示3个八进制数字,这三个数字表示字符的数字值。
	\xddd:十六进制转义字符,由一个反斜线符、一个x和一个或多个十六进制数字组成。

字符串字面值的连接:两个相邻的仅由空格、制表符或换行符分开的字符串字面值(或宽字符串字面值),可连接成一个新字符串字面值。

两种初始化变量的形式:
	(1)直接初始化(更灵活且效率更高):int ival(1024);	(2)复制初始化:int ival = 1024;

在C++中初始化不是赋值!!!

内置类型变量的初始化:在函数体外定义的变量都初始化成0,在函数体内定义的内置类型变量不进行自动初始化。

C++string类型==比较:若是字符串常量比较则直接比较地址。(编译器优化:相同的常量都引用同一处内存减少内存消耗)
	例:"abc" == "abc"返回true,"" == "\0" 返回false

extren声明变量,已初始化的extern声明被当做定义。
	约束:变量只在从其定义处开始到该声明所在的作用域结束处才可以访问。必须在使用该变量的最外层作用域里面或之前定义变量。

const对象默认为文件的局部变量,非const变量默认为extern。要使const变量能在其他文件中访问,要显式指定它为extern。

const引用:指向const对象的引用。规定将普通的引用绑定到const对象是不合法的。

非const引用只能绑定到与该引用同类型的对象。
const引用则可以绑定到不同但相关的类型的对象或绑定到右值。

用class和struct关键字定义类的唯一差别在于默认访问级别:默认情况下,struct的成员为public,而class的成员为private。

Day 2

头文件用于声明而不是定义。因为头文件包含在多个原文件中,所以不应该含有变量或函数的定义。
	3个例外:头文件可以定义类、值在编译时就已知的const对象和inline函数。原因是编译器需要它们的定义(不只是声明)来生成代码。

字符串字面值与string类型不是同一种类型。

getline(cin,str):返回时丢弃换行符,换行符不会存储在str中。

string::size_type类型:string.size()返回值类型是size_type。
	注:不能把size的返回值赋给一个int变量,因为size_type是unsigned的,赋值过程有可能会溢出。
	
安全的泛型编程:
	·C++程序员习惯于优先选用 != 而不是 < 来编写循环判断条件。
	·调用size成员函数而不保存它返回的值是一种良好的编程习惯。

vector<int>::const_iterator //它自身的值可以改变,但不能用来改变其所指元素的值。
const vector<int>::iterator //它自身的值不能改变,但可以改变其所指元素的值。

任何改变vector长度的操作都会使已存在的迭代器失效。例如,在调用push_back之后,就不能再信赖指向vector的迭代器的值了。

用unsigned值初始化bitset对象:若bitset类型长度大于unsigned对象位数,则其余高位置0;否则,超出bitset类型长度的高阶位将被丢弃。
用string对象初始化bitset对象:从string对象读入位集的顺序是从右向左。

bitset.size()返回值是size_t。

void*指针:可以保存任何类型对象的地址。仅支持几种有限的操作:
	(1)与另一指针进行比较	(2)向函数传递void*指针或从函数返回void*指针	 (3)给另一void*指针赋值

不能使用void*指针保存const对象的地址,而必须使用const void*类型的指针保存const对象的地址。

允许把非const对象的地址赋给指向const对象的指针,但不能通过该指针改变它指向的非const对象的值。

Day 3

允许动态创建空数组,返回的是有效的非零指针,不能进行解引用。

string.c_str():返回的是const char*

使用数组初始化vector:vector<int> ivec(int_arr, int_arr + arr_size); //两个参数分别指数组首位置和数组末位置的后一个位置

严格说,C++中没有多维数组,通常所指的多维数组其实就是数组的数组。

除法或求模:
	(1)两个数都为正数:除法(/)和求模(%)的结果也为正数(或零)。
	(2)两个数都为负数:除法(/)操作的结果为正数(或零);而求模(%)操作的结果为负数(或零)。
	(3)只有一个数为负数:除法 --- C++除法向零取整,即 a/b = (-a)/b = a/(-b);
						 求模 --- 根据公式:余数 = 被除数 - 商×除数
						 
对于位操作符,由于系统不能确保如何处理其操作数的符号位,所以强烈建议使用unsigned整形操作数。

移位操作的右操作数不可以是负数,而且必须是严格小于左操作数位数的值。否则,操作未定义。

*iter++等效于*(iter++)

(*p).func()等效于p->func()

对数组做sizeof操作等效于将对其元素类型做sizeof操作的结果乘上数组元素的个数。
	例:int a[5]; sizeof(a)为20;

逗号表达式的结果是其最右边表达式的值。
	例:输入一个整数,0结束	while(scanf("%d",&n),n);

if(ia[index++] < ia[index]):C++未定义此行为,不能确定是先计算左操作数还是右操作数。

值初始化语法必须置于类型名后面,而不是变量后。
	例:int *p = new int();	/*正确*/	int x(); /*错误*/

C++保证:删除0值的指针是安全的。

Day 4

switch语句:如果没有匹配的case标号(并且也没有default标号),则程序跳出switch语句。

两个case含有相同的值会报错。

若要匹配的case在default后面:default是最后执行的,只有所有的case都不匹配时才会执行,与位置无关。

在循环中定义的变量在每次循环里都要经历创建和撤销的过程。

Day 5

每次调用函数时,都会重新创建该函数所有的形参,此时所传递的实参将会初始化对应的形参。
 
在C语言中,具有const形参或非const形参的函数并无区别:
    例:void fcn(const int i){...}    void fcn(int i){...}    //两函数不能重载,会发生redefine error
     
如果使用引用形参的唯一目的是避免复制实参,则应将形参定义为const引用。
 
非const引用形参只能与完全同类型的非const对象关联。
 
应该将不需要修改的引用形参定义为const引用。普通的非const引用形参在使用时不太灵活。
这样的形参既不能用const对象初始化,也不能用字面值或产生右值的表达式实参初始化。
 
C++内置数学运算符表达式就是右值。
    如:int x = 3,y = 4; fcn(x + y); //传入函数的实参是const
 
当编译器检查数组形参关联的实参时,它只会检查实参是不是指针、指针的类型和数组元素的类型是否匹配,而不会检查数组的长度。
 
多维数组的传递:
    void f(int (*matrix)[10], int rowSize); //将matrix声明为指向含有10个int型元素的数组的指针。
    void f(int matrix[][10], int rowSize);  //用数组语法定义多维数组。 

Day 6

函数调用的实参按位置解析,默认实参只能用来替换函数调用缺少的尾部实参。

在一个文件中,只能为一个实参指定默认实参一次。通常,应在函数声明中指定默认实参,并将该声明放在合适的头文件中。
因为,如果在函数定义的形参表中提供默认是残,那么在只有在包含该函数定义的源文件中调用该函数时,默认实参才是有效的。

编译器隐式地将在类内定义的成员函数当作内联函数。

在成员函数声明的形参表后面有const:称为常量成员函数。不允许修改类的数据成员。

函数前有const,则说明函数返回值不可更改。

const对象、指向const对象的指针或引用只能用于调用其const成员函数,否则会报错。

构造函数的初始化列表(优先使用,效率较高):在冒号和花括号之间的代码称为构造函数的初始化列表。
	优势:省去了临时对象的存在。在函数体内初始化相当于在构造函数当中做赋值的操作,而初始化列表是做纯粹的初始化操作。
		  我们都知道,C++的赋值操作是会产生临时对象的。临时对象的出现会降低程序的效率。
	特殊场景:1. 类中存在const成员,那么该成员必须在初始化列表中做初始化。
			  2. 类中含有其它类B作为成员,而B类禁止掉赋值操作的情况下,那么对B的对象也只能通过初始化列表来实现。

构造函数重载与重复声明:
	重载:	  int A(int &x); 和 int A(const int &x);
	重复声明:int A(int x); 和 int A(const int x); (原因:非引用形参传递的只是副本,不能区分实参是否为const)

为了确定最佳匹配,编译器将实参类型到相应形参类型的转换划分等级。转换等级以降序排列如下:
	(1)精确匹配(exact match)。实参与形参类型相同。
	(2)通过类型提升(promotion)实现的匹配。
	(3)通过标准转换(standard conversion)实现的匹配。
	(4)通过类类型转换(class-type conversion)实现的匹配。
	
对于任意整形的实参值,int型优于short型匹配,即使short型的匹配较佳。

bool (*pf)(const string&, const string&);	//声明一个指向函数的指针pf
bool *pf(const string&, const string&);		//声明一个函数pf(...),返回值为bool*
	
函数指针只能通过同类型的函数或函数指针或0值常量表达式进行初始化或赋值。

允许将形参定义为函数类型,但函数的返回类型则必须是指向函数的指针,而不能是函数。

  

posted @ 2017-05-08 19:31  Strawberry丶  阅读(406)  评论(0编辑  收藏  举报