PS,1880后程序员

看不完的牙,写不完的程序,跑不完的步。
随笔 - 97, 文章 - 34, 评论 - 10, 引用 - 0
数据加载中……

C++ Primer 之 读书笔记 第七章

 

 

7.2 Argument Passing 参数传递

Reference Parameters引用形参

引用形参并没有对对象进行copy,而是指向它绑定的对象。

这段代码是引用形参的经典用法:

void swap(int &v1, int &v2)

{

    int tmp = v2;

    v2 = v1;    // assigns new value to local copy of the argument

    v1 = tmp;

}   

实际上,这个例子在C代码中也最常见,但是不是用引用形参,而是用指针。二者相互比较,引用形参是更加安全的写法哈。

为什么要用引用形参?

1.        Using Reference Parameters to Return Additional Information

使用引用形参返回额外的信息

2.        Using (const) References to Avoid Copies

利用 const 引用避免复制

compile错误信息:

error: invalid initialization of non-const reference of type}   

所有不可变的引用参数都应该定义成const。非const引用形参缺少灵活性。这样的形参既不能用 const 对象初始化,也不能用字面值或产生右值的表达式实参初始化。

Reference parameters that are not changed should be references to const. Plain, nonconst reference parameters are less flexible. Such parameters may not be initialized by const objects, or by arguments that are literals or expressions that yield rvalues.

形参是vector

对于vector,传递参数应该是C++ 程序员倾向于通过传递指向容器中需要处理的元素的迭代器来传递容器。(in practice, C++ programmers tend to pass containers by passing iterators to the elements we want to process

形参是array

首先不能把数组作为形参来传递。

数组参数的传递方式:

1.        通过指针传递数组。

以下形式的定义是等价的,形参都是指向数组的指针

void printValues(int*) { /* ... */ }

 void printValues(int[]) { /* ... */ }

 void printValues(int[10]) { /* ... */ }

 

2.        Passing an Array by Reference。通过引用传递数组

容易混淆的关于指针的定义:

int *matrix[10];   // array of 10 pointers

int (*matrix)[10]; // pointer to an array of 10 ints

如何在function中确定数组长度?

有三种方法:

1.        第一种方法是在数组本身放置一个标记来检测数组的结束。C 风格字符串就是采用这种方法的一个例子,它是一种字符数组,并且以空字符 null 作为结束的标记。

2.        使用标准库规范

传递指向数组第一个和最后一个元素的下一个位置的指针。

printValues(const int *beg, const int *end)

{

    while (beg != end) {

        cout << *beg++ << endl;

     }

}

3.         明确指出数组的大小。就是定义第二个参数来指明数组的大小。

7.3 返回语句 return statement

函数返回值(return value

需要定义一个临时对象-temporary object。这个对象被函数的返回值所初始化。

返回值是引用reference

Example

const string &shorterString(const string &s1, const string &s2)

     {

         return s1.size() < s2.size() ? s1 : s2;

}

 

string a1 ="123";

string a2 = "12";  

//调用

string res = shorterString(a1,a2)  ;

不能返回对局域对象的引用。

7.4 函数声明FunctionDeclarations

函数应该在头文件中声明,在源文件中实现。

定义函数的源文件中要include函数声明的头文件,例如zfmnlcom.h文件中声明了函数getExpResultFromNarrowCharBuf(),而在zfmnlcom.c文件定义了函数getExpResultFromNarrowCharBuf()

Static Local Objects

特点:

1.        作用范围是函数内部,in the scope of a function

2.        但是生存期跨越了这个函数的多次调用(whose lifetime persists across calls to the function.

3.        这类对象并不是在函数被调用时才创建的,而是在调用之前,整个程序初始化时就已经创建成功了。

7.6内联函数inline Functions

引入内联函数的目的是为了解决程序中函数调用的效率问题。

一般来说,内联机制适用于优化小的、只有几行的而且经常被调用的函数。大多数的编译器都不支持递归函数的内联。

内联函数和宏定义的区别?

想到的区别就是如果使用内联函数在编译的时候可以进行类型检查,而宏则不具备这样的功能。

例如:

#define MAX(ab) ((a)>(b)?(a):(b))

MAX(a,"Hello") //错误地比较int和字符串,没有参数类型检查

这在编译的时候是可以通过的。但是如果使用内联函数,就会在编译的时候报错。

inline int MAX(int aint b)
    {
     return a>b?a:b
    }

7.7类成员函数

C++中所说的memberJava中是属性;member functionOperationmember function的声明必须在类定

关于this

每个成员函数都有一个参数thisthis是和成员函数相关联的,而不是和Object相关联。this实际上是一个指针,指向的是调用此函数的对象。java不同,java则是Object

const成员函数

const 改变了隐含的 this 形参的类型。因此调用这个函数的对象也必须是const的。

Example

bool same_isbn(const Sales_item &rhs) const

              { return isbn == rhs.isbn; }

 

构造函数

构造函数列表

Example

Sales_item(): units_sold(0), revenue(0.0) { }

类代码文件的组织构成

l         类声明文件放在头文件header中,type.h

l         成员函数的定义放在源文件里source file。并且这个文件一定要include上面的头文件。

 

7.8. 重载函数Overloaded Functions

overload means: same function name but different parameter list.

重载与作用域Overloading and Scope

重载必须是在相同的作用域里。

Example

void print(const string &);

void print(double);   // overloads the print function

void fooBar(int ival)

{

    //注意:这不是重载,它会隐藏前面所有的print()函数定义。作用域不同

    void print(int);   // new scope: hides previous instances of print

    print("Value: ");  // error: print(const string &) is hidden

    print(ival); // ok: print(int) is visible

    print(3.14); // ok: calls print(int); print(double) is hidden

}

 

函数匹配和实参转换

这部分给出的例子真是引人入胜,读起来一气呵成。初看上去,我想答案该是调用f(int);

void f();

void f(int);

void f(int, int);

void f(double, double = 3.14);

f(5.6);  // calls void f(double, double)

错了!

函数匹配是分成3步完成的:

1.        确定候选函数Candidate Functions,筛选条件:函数名称相同的函数。

2.        选择可行函数Determining the Viable Functions,筛选条件:参数的数量和参数的类型(或者是可转换的类型)匹配的函数。

尤其要特别注意函数具有默认实参default arguments的情况。

3.        找到最匹配的 ,筛选条件:实参和形参之间互相类型最接近。

什么是“最匹配”的?

l         其每个实参的匹配都不劣于其他可行函数需要的匹配。

l         至少有一个实参的匹配优于其他可行函数提供的匹配。

其实这个问题有些拧巴了,在实际开发中,我们应该避免出现这样的情况。

转换等级以降序排列

1.        An exact match. The argument and parameter types are the same.

精确匹配。实参与形参类型相同。

2.        Match through a promotion.

通过类型提升实现的匹配。

3.        Match through a standard conversion.

通过标准转换实现的匹配。

4.        Match through a class-type conversion.

通过类类型转换实现的匹配。

形参匹配和枚举Enumerations

规则:An integral object that happens to have the same value as an enumerator cannot be used to call a function expecting an enum argument. 整数对象即使具有与枚举元素相同的值也不能用于调用期望获得枚举类型实参的函数。

 

Overloading and const Parameters重载和 const 形参

const形参只在形参类型是指针或者引用的时候才有影响。

可基于函数的形参是指向 const 对象还是指向非 const 对象,实现函数重载。

Record lookup(Account&);

Record lookup(const Account&); // new function

const Account a(0);

Account b;

lookup(a);   // calls lookup(const Account&)

lookup(b);   // calls lookup(Account&)当传递的实参是non const,两个函数都是有效的,但是要根据最佳匹配原则来匹配,把const引用指向non const对象要进行类型转换

引用和指针的道理是一样的。指针是指向const object还是nonconst object。注意这里并不是说指针是不是const的。

f(int *);

f(const int *);

7.9 指向函数的指针

函数类型取决于以下的2个条件

1.        返回值类型。return type

2.        参数列表。its parameter list

函数指针定义:

//pf是指向函数的指针,它所指向的函数带有两个 const string& 类型的形参和 bool 类型的返回值。

bool (*pf)(const string &, const string &);

括号是必须的。

简化函数指针定义:

// cmpFcn is the name of a type that is a pointer to function. cmpFcn 是一种指向函数的指针类型的名字。

typedef bool (*cmpFcn)(const string &, const string &);

// 使用,定义和初始化

cmpFcn pf1 = 0;             // ok: unbound pointer to function

cmpFcn pf2 = lengthCompare  //直接使用函数的名称而不是调用它,这个名称则是指向函数的指针

使用指针调用函数:

pf2("hi", "bye");            // equivalent call: pf1 implicitly dereferenced

(*pf2)("hi", "bye");         // equivalent call: pf1 explicitly dereferenced

函数指针也可以作为函数的形参

void useBigger(const string &, const string &,

               bool(const string &, const string &));

void useBigger(const string &, const string &,

               bool (*)(const string &, const string &));

返回值也可以是函数指针:

int (*ff(int))(int*, int);

不得不说,抓狂啊。这种恐怖的写法能够正确写出来就已经是强人了J

理解:

ff(int)

函数ff,有1int形参。

int (*)(int*, int);

返回值是1个函数指针,这个函数指针指向的函数的有2个参数int*, int并且返回值是int

不过如果使用typedef,就好理解一些哈

typedef int (*PF)(int*, int);

PF ff(int);  // ff returns a pointer to function

函数类型可以作为形参,但是只有函数指针能够作为返回值。

 

posted on 2009-05-20 14:22 amenglai 阅读(453) 评论(0)  编辑  收藏 所属分类: C++ Primer 之 读书笔记


只有注册用户登录后才能发表评论。


网站导航: