P307:
函数调用做了两件事情:用对应的实参初始化函数的形参,并将控制权转移给被调用函数。主调函数的执行被挂起,被调函数开始执行。函数的运行以形参的(隐式)定义和初始化开始。
P308:
函数不能返回另一个函数或者内置数组类型,但可以返回指向函数的指针,或指向数组元素的指针的指针。
注:C++还是很强大的。
P314:
复制实参的局限性
复制实参不适宜的情况:
1. 当需要再函数中修改实参的值时;
2. 当需要以大型对象作为实参传递是。复制对象所付出的时间和存储空间代价往往过大;
3. 当没有办法实现对象的复制时。
有效的解决办法是将形参定义为引用或指针类型。
注:啥时候我也能靠分析而不是死记侃侃而谈呀。
P316:
从C语言背景转到C++的程序员习惯通过传递指针来实现对实参的访问。在C++中,使用引用形参则更安全和更自然。
注:看来我的想法要从C转变到C++才可以。
P316:
使用引用形参返回额外的信息。
一个例子:
// returns an iterator that refers to the first occurance of value
// the reference parameter occurs contains a second return value
vector<int>::const_iterator find_val(vector<int>::const_iterator beg, //first element
vector<int>::const_iterator end, // last element
int value, // the value we want
vector<int>::size_type &occurs) // number of time it occurs
{
// res_iter will hold first occurence, if any
vector<int>::const_iterator res_iter = end;
occurs = 0; // set occurence count parameter
for (; beg != end; ++beg)
{
if (*beg == value)
{
// remember first occurrence of value
if (res_iter == end)
{
res_iter = beg;
}
++occurs; // increment occurence count
}
}
return res_iter; // count returned implicitly in occurs
}
可如此调用:
<span style="font-family:Microsoft YaHei;">it = find_val(ivec.begin(), ivec.end(), 42, ctr);</span>
注:差距。如果要我实现功能类似的函数,一定是一大堆数组,一大堆指针,首先思维要扭转过来。P318:
*更灵活的指向const的引用
应该将不修改相应实参的形参定义为const引用。例如:
// returns index of first occurence of c in s or s.size() if c isn't in s
// Note: s doesn't change, so it should be a reference to const
string::size_type find_char(string &s, char c)
{
string::size_type i = 0;
while(i != s.size() && s[i] != c)
++i; // not found, look at next character
return i;
}
这样定义的问题是不能通过字符串字面值来调用这个函数:
if (find_char("Hello World", 'o')) //...
上述调用会导致编译失败。
即使程序本身没有const对象,而只使用string对象调用find_char函数,编译阶段的问题依然会出现,例如,另一个函数is_sentence调用find_char来判断一个string对象是否是句子:
bool is_sentence(const string &s)
{
// if there's a period and it's the last character in s
// then s is a sentence
return (find_char(s, '.') == s.size() -1);
}
传递进is_sentence的形参是指向const_string对象的引用,不能讲这种类型的参数传递给find_char,因为后者期待得到一个指向非const string对象的引用。
应该将不需要修改的引用形参定义为const引用。普遍的非const引用形参在使用时不太灵活。这样的形参既不能用const对象初始化,也不能用字面值或产生右值的表达式实参初始化。
注:之前编码的时候出现过好多次类似的编译错误,都没有太放在心上,好像摆弄一下就能编译通过,其实已经在代码中埋下了隐患,不是合理的设计。
P322:
*vector和其他容器类型的形参
通常,函数不应该有vectro或其他标准库容器类型的形参。调用含有普通的非引用vector形参的函数将会复制vector的每一个元素。
从避免复制vector的角度出发,应考虑将形参声明为引用类型。事实上,C++程序员倾向于通过传递指向容器中需要处理的元素的迭代器来传递容器:
// pass iterators to the first and one past the last element to print
void print(vector<int>::const_iterator beg,
vector<int>::const_iterator end)
{
while (beg != end)
{
cout << *beg++;
if (beg != end)
{
cout << " "; // no space after last element
}
}
cout << endl;
}
注:很好的经验。
P326:
*matrix两边的园括号是必需的:
int *matrix[10]; // array of 10 pointers
int (*matrix)[10]; // pointer to an array of 10 ints
P327:
有三种常见的编程技巧确保函数的操作不超出数组实参的边界:
1. 在数组本身放置一个标记来检测数组的结束。处理C风格字符串的程序就是使用这个标记停止数组元素的处理(NULL)。
2. 传递指向数组第一个和最后一个元素的下一个位置的指针。这种编程风格由标准库所使用的技术启发而得。
3. 将第二个形参定义为表示数组的大小,这种用法在C程序和标准化C++程序中十分普遍。
P329:
int main(int argc, char *argv[]) { ... }
第二个形参argv是一个C风格字符串数组。第一个形参argc则用于传递该数组中字符串的个数。
P330:
含有可变形参的函数
注:没看懂,因为之前没有用过可变形参,从来没有弄明白过。
http://punch.blog.163.com/blog/static/2285731201092894021668/,这篇还不错,弄明白一点点了。
P333:
主函数main的返回值:
cstdlib文件头文件定义了两个预处理变量,分别用于表示程序运行成功和失败:
#include <cstdlib>
int main()
{
if (some_failure)
{
return EXIT_FAILURE;
}
else
{
return EXIT_SUCCESS;
}
}
P338:
递归函数必须定义一个终止条件;否则,函数就会“永远”递归下去,这意味着函数会一直调用自身直到程序栈耗尽。有时候,这种现象称为“无限递归错误”。
注:有一次面试的时候就忘记了写递归终止条件。
P339
函数原型为定义函数的程序员和使用函数的程序员之间提供了接口。在使用函数时,程序员只对函数原型编程即可。
把函数声明直接放到每个使用该函数的源文件中,这可能是大家希望的方式,而且也是合法的。但问题在于这种用法比较呆板而且容易出错。解决的方法是把函数声明放在头文件中,这样可以确保对于指定函数其所有声明保持一致。
注:接口,接口,这个出现频繁的词,原来是这个意思。
P343:
既可以在函数声明也可以在函数定义中指定默认实参。但是,在一个文件中,只能为一个形参指定默认实参一次。
通常,应在函数声明中指定默认实参,并将该声明放在合适的头文件中。
注:默认实参的正确用法。
P345:
一个变量如果位于函数的作用域内,但生命期跨越了这个函数的多次调用,则应该将这样的对象定义为static(静态的)。
注:我喜欢静态变量,看起来很cool。
P347:
inline函数避免函数调用的开销
把inline函数放在头文件,确保在调用函数时所使用的定义时相同的,并且保证在调用点该函数的定义对编译器课件。
P350:
this指针的引入
每个成员函数(static成员函数除外)都有一个额外的,隐含的形参this。
total.same_isbn(trans);
编译器会这样重写这个函数调用:
// pseudo-code illustration of how a call to a member function is translated
Sales_item::same_isbn(&total, trans);
P351:
const成员函数的引用
跟在成员函数声明的形参表后面的const所起的作用:const改变了隐含的this形参的类型。
用这种方式使用const的函数称为常量成员函数。由于this指向const对象的指针,const成员函数不能修改调用该函数的对象,只能读取而不能修改。
注:soga,之前一直没有弄明白跟在成员函数后面的const的含义。
P335:
合成的默认构造函数一般适用于包含类类型成员的类。而对于含有内置类型或复合类型成员的类,则通常应该定义他们自己的默认构造函数初始化这些成员。
P358:
如果两个函数声明的返回类型和形参表完全匹配,则将第二个函数声明视为第一个的重复声明。如果两个函数的形参表完全相同,但返回类型不同,则第二个声明是错误的:
Record lookup(const Account&);
bool lookup(const Account&); // error:only return type is different
函数不能仅仅基于不同的返回类型而实现重载。
P361:
在C++中,名字查找发生在类型检查之前。
P365:
在实际应用中,调用重载函数时应尽量避免对实参做强制类型转换:需要使用强制类型转换意味着所设计的形参集合不合理。
注:平时使用中没有注意到的,在使用GDI+相关调用时,为了让编译通过,经常使用强转,需要改掉这个坏习惯。重载这一节讲的比较多,没有太仔细看,如果以后有不明白的地方再回来好好看看重载的分析吧。
P370:
指向函数的指针
// pf points to function returning bool that takes two const string references
bool (*pf)(const string&, const string&);
*pf两侧的圆括号是必须的:
// declares a function named pf that returns a bool*
bool *pf(const string &, const string &);
用typedef简化函数指针的定义
typedef bool (*copFcn)(const string &, const string &);
cmpFcn是一种指向函数的指针类型的名字。要使用这种函数指针类型时,只需直接使用cmpFcn即可,不必每次都把整个类型声明全部写出来。
注:第七章还有一小部分没有看完,但是有点累了,休息了。——201406081800
P373
函数指针形参
/* useBigger function's third parameter is a pointer to function
* that function returns a bool and takes two const string references
* two ways to specify that parameter:
*/
// third parameter is a function type and is automatically treated as a pointer to function
void useBigger(const string &, const string &,
bool(const string &, const string &));
// equivalent declaration: explicitly define the parameter as a pointer to function
void useBigger(const string &, const string &,
bool (*)(const string &, const string &));