1.重载函数,也就是说一个名字可以对应几个不同的函数。
2.内置类型的未初始化局部变量将产生未定义的值。
3.局部静态对象在程序执行路径第一次进过对象定义语句时初始化,并且直到程序终止才被销毁。
内置类型的局部静态变量初始化为0.
4.函数的声明也称函数原型。
5.含有函数声明的头文件应该被包含到定义函数的源文件中。(来让编译器验证函数的定义和声明是否匹配)
6.熟悉C语言的程序员常常使用指针类型的形参访问函数外部的对象。在C++语言中,建议使用引用类型的形参代替指针。
7.如果函数无需改变引用形参的值,最好将其声明为常量引用。
8.在C++语言中,允许我们定义若干具有相同名字的函数,不过前提是不同函数的形参列表应该有明显的区别。
9.我们可以使用非常量值初始化一个底层const对象,但是反过来不行(非常量指针不能指向常量)。普通引用必须用同类型的对象初始化。
10.使用引用而非常量引用也会极大的限制函数所能接受的实参类型。
11.数组引用形参的写法:
f(int (&arr)[10])
(&arr)这个括号必不可少,不然就变成了引用数组了f(int &arr[10])
数组指针同理,应该写为 f(int (*arr)[]),并且与f(int arr[][10])是类似等价的。
12.当使用argv中的实参时,一定要记得可选的实参从argv[1]开始,argv[0]保存当前程序的名字,而非用户输入。
13.如果形参的数量未知,但是全部的实参的类型都是相同已知的,可以使用initiaizer_list类型的形参,他的用法同vector,详见C++Prime p197.
14.返回数组指针函数的定义方式:运用重定义
typedef int arrT[10];
using arrT = int[10];
arrT* func(int i);
15.假如有两个函数,它们的形参列表函数名字都一样,但是返回类型不一样,则第二个函数声明是错误的。
16.调用重载函数的过程:
顶层const不影响传入函数的对象。
函数匹配-----重载确定 (三种情况)-> 最佳匹配 ->无匹配 ->二义性调用(有多余一个函数可以匹配,但是每一个都不是明显的最佳选择。)
17.在C++语言中,名字查找发生在类型检查之前。
18.默认实参作为形参的初始值出现在形参列表中。一旦某个形参被赋予了默认值,它后面的所有形参都必须有默认值。
默认实参的放置顺序:尽量让不怎么使用默认值的形参出现在前面,而让那些经常使用默认值的形参出现在后面。
通常,应该在函数声明中指定默认实参,并将该声明放在合适的头文件中。
19.预处理宏:assert在头文件cassert中
表达式: assert(expr);
先对表达式求值,如果为真,什么也不做,如果为假,输出信息并终止程序执行。
而assert依赖于NDEBUG预处理变量,默认状态下没有定义这个变量,一旦定义了,assert什么都不做。
20.所有算术类型转换的级别都一样。例如从int 到unsigned int 的转换并不比从int 向double高
21.声明函数指针:
函数原型:
bool lengthCompare(const string &,const string &);
则指向这个函数的指针可以定义为
bool (*pf)(const string &,const string &);
*pf的两边的括号必不可少,否则就定义了一个返回类型是bool指针的函数
给函数指针赋值或者是调用时候,&,*可用可不用,效果相同
例如:
pf = lengthCompare;
pf = &lengthCompare;//两者等价,因为当我们把函数名作为一个值使用时,会自动转换为指针。
bool b1 = pf(......);
bool b2 = *pf(.......);这两者也等价。
22.当我们将decltype作用于某个函数时,它返回函数类型而非指针类型。因此,我们显式的加上*以表明我们需要返回指针,而非函数本身。
23.IO类属于不能被拷贝的类型,因此将io类型的参数传入的时候,只能通过引用来进行。
24.定义类中执行输出任务的函数的时候应该尽量减少对格式的控制,这样可以确保由用户代码来决定是否换行。
25.构造函数,名字与类名相同,类中控制对象初始化的函数。无论何时,只要类被创建,就会自动执行构造函数。
不能被声明为const.
26.默认构造函数只能用于简单的类的原因:
①一个类如果在某种情况下需要控制对象初始化,那么该类很有可能在所有情况下都需要控制。(只有当类中没有声明任何构造函数的时候,编译器才会自动的生成默认构造函数)
②如果类内包含有内置类型或者是复合类型,这时使用默认构造函数,那些量的结果是未知的。
③如果类中包含其他类型的成员,且这个成员没有默认构造函数,那么编译器无法初始化该成员。
27.人为的定义合成的默认构造函数:Sale_data() = default;
构造函数:Sale_data(const std::string &s,unsigned n,double p):bookNo(s),units_sold(n),revenue(p*n){};
28.构造函数的用法:在定义的时候直接在对象名后面加括号,括号里面加上要输给构造函数的参数即可。例子:
Sales_data item3("0-201-78345-X", 3, 20.00);
29.使用访问说明符和class,struct来封装类
pubilic访问说明符之后定义接口。
private分装类的实现细节。
访问说明符的有效范围直到出现下一个访问说明符或者到达类的结尾处为止。
例子:
class Sale_data{
public:
Sale_data() = default;
Std::string isbn() const {return bookNo;}
Sale_data &combine(const Sale_data&)
private:
double avg_price() const {return units_sold ? revenue/units_sold : 0;}
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
x
10
1
class Sale_data{
2
public:
3
Sale_data() = default;
4
Std::string isbn() const {return bookNo;}
5
Sale_data &combine(const Sale_data&)
6
private:
7
double avg_price() const {return units_sold ? revenue/units_sold : 0;}
8
std::string bookNo;
9
unsigned units_sold = 0;
10
double revenue = 0.0;
11
};
30.class和struct的区别,在上例中两者可以替换,两者的唯一区别就是在第一个访问说明符之前定义的成员的默认访问方式的不同,class处理为private,struct处理为public.
31.封装优点:
①用户代码不会无意间破环封装对象的状态。
②被封装的类的具体实现细节可以随时改变,而无须调整用户级别的代码。
32.类可以允许其他类或者函数访问他的非公有成员,方法是令其他类或者函数成为它的的友元,只需增加一条以friend关键字开始的函数声明语句即可。我们必须在元友声明之外再专门对函数进行一次声明。(虽然很多编译器没有强制要求声明,也可以调用那个函数)但是为了可移植性,还是提供一个独立的声明。
在类块中位置不限,例子:
class Sale_data {
friend Sale_data add(const Sale_data &,const Sales_data&);
public:........
......
.....
};
33.可变数据成员:通过在变量的声明前加入mutable关键字,可以定义一个可变数据成员,这个成员永远不会是const,即使它是const对象的成员。
34.类内初始值必须使用=的初始化形式,或者花括号括起来的直接初始化形式。
35.即使两个类的成员列表完全一致,它们也是不同的类型。
36.C++中可以直接使用类名或者struct /class加类名表示类型,后者是从C继承来的。
37.类可以把其他类,其他类的成员函数定义成友元。友元关系不存在传递性。