1、数据抽象,是指将对象的具体实现与对象所能做的操作分离开来。其依赖于接口与实现分离的编程,类的接口包括了用户所能执行的操作,而类的实现包括了类的数据成员、接口实现的函数体以及定义类所需的私有的各种私有函数。
2、封装使得类的用户只能使用接口,而无法访问实现的内容。想实现数据抽象和封装,要先定义一个抽象的数据类型,在抽象数据类型中,由设计者负责考虑类的实现过程,使用该类的程序员只需要知道该类用来做什么,不需要知道其设计细节。
3、判断一个类是否是抽象数据类型,只需要判断类的用户能否直接访问类中的数据成员。
4、类的设计者--->类的用户(程序员)--->用户(使用程序的人)。
5、成员函数必须声明在类的内部。作为接口组成部分的非成员函数,其声明与定义在类外部。并且定义在类内部的函数是隐式的inline函数。
6、当我们调用成员函数时,实际上是替某个对象调用该函数。成员函数通过一个名为this的隐式参数来访问调用它的对象,也就是说,一个对象在调用成员函数时,会用这个对象地址去初始化this指针,也就是说this指针在某个对象调用成员函数时,this指针就是指这个对象。任何对类成员的直接访问,都看作是this的隐式引用。并且this是一个指针常量,不能修改this的值。
7、在成员函数形参表后加上const的作用是修改隐式this指针的类型。由于this指针是一个指针常量,其指向类类型非常量版本,因此在默认情况下不能用一个常量对象去初始化指针常量。而在成员函数参数表后面加上const(常量成员函数),表示this指针是指向常量的指针常量。
8、当一个函数返回的是this指针,表示返回调用这个函数的对象。使用this指针的好处:可以明确的指出使用的是对象的成员,并且在成员函数中,可以在成员函数中使用与数据成员同名的形参。
9、类的作者经常要定义一些辅助函数,这些辅助函数不是类的成员函数,在概念上,它们属于类的接口组成部分,也就是说概念上属于类,但是不在类中定义,一般与类声明放在一个头文件里。
10、IO类属于不可拷贝的类型。只能使用引用的类型。执行输出任务的函数一般尽量减少对格式的控制。
11、只要类的对象被创建,那么就会执行构造函数。构造函数不能被声明为const类型。构造函数可以在常量对象的构造过程中向其写值,只有当构造函数初始化过程结束后,对象才能取其的const属性。
12、编译器创建的构造函数又被称为合成默认构造函数,若存在类内的初始值,则用其初始化成员,否则执行默认初始化。
13、某些类不能依赖于默认构造函数,需要自己给它定义一个默认构造函数,有三点原因:1)当我们自己定义了默认构造函数,编译器就不会再定义默认构造函数
2)在类内的成员可能是内置类型或者复合类型,需要在类内就对其进行初始化,否则可能会得到未定义的值。
3)可能一个类中还包含着其他类类型的成员,这时候若这个其他类成员没有默认构造函数,那么将无法对其进行初始化,这时候编译器无法生产一个默认的构造函数。
14、C++11标准下,可以使用=default来使编译器生成一个默认的构造函数。其即可以作为声明在类的内部,作为内联函数,也可以作为定义在类的外部,这时就不是内联函数。
15、当某个数据成员被构造函数初始化列表忽略时,它将采用类内初始值(以默认构造函数的方式进行隐式地初始化)。
16、若你的编译器不支持类内初始值,那么所有的数据成员都应该显式地初始化每个成员。
17、使用this是将其看成对象整体,对其解引用得到的是对象。
18、初始化变量和以值的方式进行传递或者返回一个对象等都会出现拷贝行为。一般情况下,编译器生成的版本会对对象的每个成员执行拷贝赋值销毁的操作。所谓合成的版本是指编译器替我们执行拷贝赋值销毁的操作。
19、若类包含了vector或者string成员,则其拷贝赋值销毁能正常工作,但是很多类当要分配对象之外的资源时,合成版本通常会失效。
20、每个访问符指定了成员访问的级别,知道遇到下一个访问符或者类的结尾才结束。struct和class定义类的唯一区别就是访问权限不一样,前者默认是public,后者是private。
21、封装的两个优点:1)防止用户代码无意间破坏了封装对象的状态。2)被封装的具体实现细节可以随时改变,不需要调整用户级别的代码。
22、若想要类外部的函数能访问类中的私有成员,可以将这些函数声明成友元函数,友元函数声明只能出现在类定义的内部,具体位置不限。
23、在类内声明了友元函数只是指明其访问权限,若类的用户想调用友元函数,那么需要在类的外部再声明一次友元函数,并且一般情况下,类与友元函数的声明放在同一个文件中。
24、一旦使用友元函数不当就会破坏掉类的封装性,注意:将非成员函数声明成友元函数,只是让友元函数“住”在类内,并不是类内的成员函数,但是它能跟成员函数一样访问类内所有成员。
25、在类中除了可以定义数据和数据成员外,还可自定义类型在类中的别名,并且也具有访问权限。用来定义类型的成员必须先定义后使用,类型成员一般在类的开头定义。
26、可以在类的内部把inline作为声明部分显示地声明成员函数,也可以在类的外部用inline修饰函数的定义。最好只在类外部定义的地方说明inline,可以使类更容易理解,也就是说inline函数应该与相应的类定义放在同一个文件中。
27、类的成员函数的重载与非成员函数非常类似。
28、若想在一个const对象里面也能修改成员,可以通过加入mutable关键字实现,这样通过该关键字定义的数据成员,即使在const成员函数内,也可以修改其数据成员,这种数据成员就是可变数据成员。
30、若想一个类在开始的时候都能拥有另一个默认初始化类。可以将后者的默认值声明成前者类的类内初始值。当我们提供一个类内初始值时,必须以符号=或者花括号表示。
31、将类中的成员函数定义成inline函数,可以进行隐式内联:在类中定义成员函数;也可以进行显式内联:在类外部定义成员函数并显式指定inline关键字。
32、返回引用的函数是左值,表示其返回的对象本身而非对象副本。一个常量成员函数若返回引用,则其返回类型应该为常量引用。
33、与普通函数的形参是否是底层const,可以进行重载,类似,类的成员函数是否是const类型,可以进行重载。
34、对于公共代码使用私有功能函数,有以下几点原因:1)避免在多处使用相同代码;2)可能在私有功能函数会添加一些调试信息,在产品发布后需要去掉会显得容易;3)额外的函数不会增加任何开销,因为在类内定义的属于隐式内联函数。
35、类名不同,类内成员完全一样,两者也是不同的类类型。可以直接将类名作为类型名字,直接指向类类型。若一个类只有前向声明,而没有定义,则其是不完全类型。可以定义指向不完全类型的指针或引用,也可以声明该类型作为参数或返回值的函数,但是不能定义。只有当类被定义了,类定义的对象才有空间大小,因此,才能用指针和引用去访问类的成员。只有当类全部完成后,类才是被定义,所以不能在类中定义自己类类型的成员。但是只要类声明了,就允许包含指向它自身类型的引用或者指针。
36、类可以把其他类定义成友元,也可以把其他类(之前已经定义过)的成员函数定义成友元,友元关系不具有传递性。若想指定其他类的成员函数为友元时,在声明时需要指定其属于哪个类。
37、当一个类或者函数的名字,第一次出现在一个友元声明里,那么就隐式地假定该名字在当前作用域可见。友元函数本身不一定被声明在作用域里面。
38、在类的内部定义友元函数,也必须在类的外部提供相应的声明,从而是函数可见。有的编译器并不强制限定这些规则。
39、构造函数中,对象的成员的初始化和赋值有区别,使用初始值列表属于初始化操作,而在构造函数体中赋值,属于赋值操作,两者是否等价依赖于成员的类型。初始化还是赋值操作,其实涉及到底层效率,前者只是初始化,后者是初始化后再赋值。
40、构造函数的成员初始化顺序与它定义成员的顺序一样。尽量避免使用某些成员初始化其他成员。一般情况下,最好使用构造函数的参数去初始化成员。
41、如果一个构造函数的所有参数都有默认实参,那么它实际上也定义了默认的构造函数,或者说起到默认构造函数的作用。
42、C++11标准下,扩展了构造函数,允许我们定义委托构造函数,所谓委托构造函数就是将其部分或者全部的任务给同属类的其他构造函数完成。委托构造函数的初始化列表只有唯一的入口,即类名本身。
43、当委托构造函数委托的构造函数体中有代码,先执行委托的构造函数的代码,完成后,控制权才交还给委托构造函数。
44、在实际中,如果定义了其他构造函数,最好也提供一个默认构造函数。
45、聚合类,可以使用户访问其类内的所有成员,其满足以下特征:1)类内所有成员都是public的;2)类内没有定义任何构造函数;3)没有类内初始值;4)没有基类,也没有虚函数。
46、使用一个花括号括起来的初始值列表初始化聚合类的成员,并且花括号中的初始值必须与声明成员的顺序一致,并且初始值的个数不能大于成员数量。显式地初始化类的对象的成员在添加和删除一个成员后,要更新所有的初始化语句。
47、当我们想让一个成员与类相关联,而不是与类的对象相关联时,可以使用类的静态成员;
48、能通过一个实参调用的构造函数定义了一条从构造函数的参数类型像类类型隐式转换的规则。