1.用来初始化枚举成员的值必须是一个常量表达式。每个 enum 都定义一种唯一的类型
枚举一定义,编译器就要保证值不能变
2.每个类都定义了一个接口和一个实现。接口由使用该类的代码需要执行的操作组成。实现一般包括该类所需要的数据。
3.编程新手经常会忘记类定义后面的分号,这是个很普遍的错误!
4.C++ 支持另一个关键字 struct,它也可以定义类类型。
用 class 和 struct 关键字定义类的唯一差别在于默认访问级别:默认情况下,struct 的成员为 public,而 class 的成员为 private。
5.对于头文件不应该含有定义这一规则,有三个例外。头文件可以定义类、值在编译时就已知道的 const 对象和 inline 函数
6.内联函数,将 shorterString 写成函数有一个潜在的缺点:调用函数比求解等价表达式要慢得多。在大多数的机器上,调用函数都要做很多工作;调用前要先保存寄存器,并在返回时恢复;复制实参;程序还必须转向一个新位置执行。
把 inline 函数放入头文件,因为inline 函数的定义对编译器而言必须是可见的,以便编译器能够在调用点内联展开该函数的代码。此时,仅有函数原型是不够的。而且,内联函数本身是不被分配内存的。只有展开的地方才分配内存,所以可以多次定义。
编译与链接
7.预处理器用指定的头文件的内容替代每个 #include。
8.当进行 string 对象和字符串字面值混合连接操作时,+ 操作符的左右操作数必须至少有一个是 string 类型的:
string st1, st2 = "The expense of spirit";
st1 = st2; // replace st1 by a copy of st2
它必须先把 st1 占用的相关内存释放掉,然后再分配给 st2 足够存放 st2 副本的内存空间,最后把 st2 中的所有字符复制到新分配的内存空间。然后,再将s1指向s2副本。想一想,为什么不直接将s2中的字符直接复制到s1中。因为不知道s2到底有多大。
下标操作可用作左值
for (string::size_type ix = 0; ix != str.size(); ++ix)
str[ix] = '*';
和字符串字面值的连接
string s5 = s1 + ", " + "world"; // ok: each + has string operand
string s6 = "hello" + ", " + s2; // error: can't add string literals
9.vector 不是一种数据类型,而只是一个类模板,可用来定义任意多种数据类型。vector 类型的每一种都指定了其保存元素的类型。因此,vector<int> 和 vector<string> 都是数据类型。
vector<int> ivec1; // ivec1 holds objects of type int
vector<int> ivec2(ivec1); // ok: copy elements of ivec1 into ivec2
vector<string> svec(ivec1); // error: svec holds strings, not ints
一些有自定义构造函数但没有默认构造函数的类,在初始化这种类型的 vector 对象时,程序员就不能仅提供元素个数,还需要提供元素初始值。
vector 对象(以及其他标准库容器对象)的重要属性就在于可以在运行时高效地添加元素。因为 vector 增长的效率高,在元素值已知的情况下,最好是动态地添加元素。
成员函数 size 返回相应 vector 类定义的 size_type 的值。
使用 size_type 类型时,必须指出该类型是在哪里定义的。vector 类型总是包括总 vector 的元素类型: |
vector<int>::size_type // ok
vector::size_type // error
for (vector<int>::size_type ix = 0; ix != ivec.size()/*动态增长*/; ++ix)
ivec[ix] = 0;
A.重载成员:要求
两个重载成员的形参数量和类型不能完全相同
B.为什么类的定义以分号结束:class Sales_item { /* ... */ } accum, trans;
c.定义一个类时,也就是定义了一个类型。一旦定义了类,就可以定义该类型的对象。定义对象时,将为其分配存储空间,但(一般而言)定义类型时不进行存储分配
可以声明一个类而不定义它:
class Screen; // declaration of the Screen class
因为,类定义但不分配内存,所以可以在多个cpp文件中定义,但不能在同一个cpp中多次定义。也可以看出编译是每个文件独立编译的。链接时才统一到一起。
只有当类定义已经在前面出现过,数据成员才能被指定为该类类型。如果该类型是不完全类型,那么数据成员只能是指向该类类型的指针或引用。如
class LinkScreen {
Screen window;
LinkScreen *next;
LinkScreen *prev;
};
Class screen;
Screen *s;
D.Const 成员函数。
const 对象、指向 const 对象的指针或引用只能用于调用其 const 成员函数,如果尝试用它们来调用非 const 成员函数,则是错误的。
在普通的非 const 成员函数中,this 的类型是一个指向类类型的 const 指针(第 4.2.5 节)。可以改变 this 所指向的值,但不能改变 this 所保存的地址。在 const 成员函数中,this 的类型是一个指向 const 类类型对象的 const 指针。既不能改变 this 所指向的对象,也不能改变 this 所保存的地址。
不要把 const_iterator 对象与 const 的 iterator 对象混淆起来。声明一个 const 迭代器时,必须初始化迭代器。一旦被初始化后,就不能改变它的值:
vector<int> nums(10); // nums is nonconst
const vector<int>::iterator cit = nums.begin();
*cit = 1; // ok: cit can change its underlying element
++cit; // error: can't change the value of cit
E.没有所有元素都是引用的数组。
F.非 const 变量以及要到运行阶段才知道其值的 const 变量都不能用于定义数组的维数。
// both buf_size and max_files are const
const unsigned buf_size = 512, max_files = 20;
int staff_size = 27; // nonconst
const unsigned sz = get_size(); // const value not known until run time
char input_buffer[buf_size]; // ok: const variable
string fileTable[max_files + 1]; // ok: constant expression
double salaries[staff_size]; // error: non const variable
int test_scores[get_size()]; // error: non const expression
int vals[sz]; // error: size not known until run time
const char ch3[6] = "Daniel"; // error: Daniel is 7 elements