C-PRIMER PLUS读书笔记

   CHAPTER 8 ADVENTURES IN FUNCTIONS

lnline function
什么是内联函数?
           相对于一般函数调用,内联函数程序无需跳到另一位置处执行代码,然后再挑回来。因此内联函数的运行速度要比常规函数稍快,但代价是需要占用更多的内存。如果程序在十个不同的地方调用同一个函数,则该程序将包含该函数的十个代码拷贝

什么情况下使用内联函数?
            如果执行函数代码的时间大于函数调用机理的时间长。不用
            执行代码时间短。用

使用时采取下述措施:
  • 在函数声明前加上关键字 inline
  • 在函数定义前加上关键字 inline
 通常的做法是省略原型,将整个定义(即函数头和所有函数代码)放在本应提供原型的地方。inline.cpp
Listing 8.1 inline.cpp
// inline.cpp -- use an inline function
#include <iostream>
using namespace std;

// an inline function definition
inline double square(double x) { return x * x; }

int main()
{
double a, b;
double c = 13.0;

a = square(5.0);
b = square(4.5 + 7.5); // can pass expressions
cout << "a = " << a << ", b = " << b << "/ n";
cout << "c = " << c;
cout << ", c squared = " << square(c++) << "/ n";
cout << "Now c = " << c << "/ n";
return 0;
}

Reference variable--引用变量



         

 

引用变量的定义:

c++新增了一种复合类型--引用变量。引用是已定义的变量的别名。

// firstref.cpp -- defining and using a reference
#include <iostream>
using namespace std;
int main()
{
int rats = 101;
int & rodents = rats; // rodents is a reference
cout << "rats = " << rats; cout << ", rodents = " << rodents << "/ n"; rodents++; cout << "rats = " << rats; cout << ", rodents = " << rodents << "/ n"; // some implementations require type casting the following // addresses to type unsigned cout << "rats address = " << &rats; cout << ", rodents address = " << &rodents << "/ n"; return 0; }
记住:必须在声明引用的同时进行初始化。
int & rodents = rats; 

is, in essence, a disguised notation for something like this:

int * const pr = &rats; 
Listing 8.3 secref.cpp
// secref.cpp -- defining and using a reference
#include <iostream>
using namespace std;
int main()
{
int rats = 101;
int & rodents = rats; // rodents is a reference

cout << "rats = " << rats;
cout << ", rodents = " << rodents << "/ n";

cout << "rats address = " << &rats;
cout << ", rodents address = " << &rodents << "/ n";

int bunnies = 50;
rodents = bunnies; // can we change the reference?
cout << "bunnies = " << bunnies;
cout << ", rats = " << rats;
cout << ", rodents = " << rodents << "/ n";

cout << "bunnies address = " << &bunnies;
cout << ", rodents address = " << &rodents << "/ n";
return 0;
}
In short, you can set a reference by an initializing declaration, not by assignment.
8.2.2将引用作函数参数
Most often, references are used as function parameters, 
making a variable name in the function an alias for a variable in the calling program. 
This method of passing arguments is called passing by reference.
Listing 8.4 swaps.cpp
// swaps.cpp -- swapping with references and with pointers
#include <iostream>
using namespace std;
void swapr(int & a, int & b); // a, b are aliases for ints
void swapp(int * p, int * q); // p, q are addresses of ints
void swapv(int a, int b); // a, b are new variables
int main()
{
int wallet1 = 300;
int wallet2 = 350;

cout << "wallet1 = ___FCKpd___11quot; << wallet1;
cout << " wallet2 = ___FCKpd___11quot; << wallet2 << "/ n";

cout << "Using references to swap contents:/ n";
swapr(wallet1, wallet2); // pass variables
cout << "wallet1 = ___FCKpd___11quot; << wallet1;
cout << " wallet2 = ___FCKpd___11quot; << wallet2 << "/ n";

cout << "Using pointers to swap contents:/ n";
swapp(&wallet1, &wallet2); // pass addresses of variables
cout << "wallet1 = ___FCKpd___11quot; << wallet1;
cout << " wallet2 = ___FCKpd___11quot; << wallet2 << "/ n";

cout << "Trying to use passing by value:/ n";
swapv(wallet1, wallet2); // pass values of variables
cout << "wallet1 = ___FCKpd___11quot; << wallet1;
cout << " wallet2 = ___FCKpd___11quot; << wallet2 << "/ n";
return 0;
}

void swapr(int & a, int & b) // use references{
int temp;

temp = a; // use a, b for values of variables
a = b;
b = temp;
}

void swapp(int * p, int * q) // use pointers
{
int temp;

temp = *p; // use *p, *q for values of variables
*p = *q;
*q = temp;
}

void swapv(int a, int b) // try using values
{
int temp;
temp = a; // use a, b for values of variables
a = b;
b = temp;
}
in swapr() the variables a and b serve as aliases for wallet1 and wallet2, 
so swapping a and b swaps wallet1 and wallet2. But in swapv(), 
the variables a and b are new variables that copy the values of wallet1 and wallet2, 
so swapping a and b has no effect on wallet1 and wallet2.
8.2.3引用的属性和特别的地方
Listing 8.5 cubes.cpp
// cubes.cpp -- regular and reference arguments
#include <iostream>
using namespace std;
double cube(double a);
double refcube(double &ra);
int main ()
{
double x = 3.0;

cout << cube(x);
cout << " = cube of " << x << "/n";
cout << refcube(x);
cout << " = cube of " << x << "/n";
return 0;
}

double cube(double a)
{
a *= a * a;
return a;
}

double refcube(double &ra)
{
ra *= ra * ra;
return ra;
}
Note that the refcube() function modifies the value of x in main() whereas cube() doesn't, 
which reminds us of why passing by value is the norm. 
Temporary Variables, Reference Arguments, and const

First, when is a temporary variable created? Provided that the reference parameter is a const, the compiler generates a temporary variable in two kinds of situations:

  • The actual argument is the correct type, but isn't an Lvalue

  • The actual argument is of the wrong type, but of a type that can be converted to the correct type

An argument that's an Lvalue is a data object that can be referenced. For example, a variable, an array element, a structure member, a reference, and a dereferenced pointer are Lvalues. Non-Lvalues include literal constants and expressions with multiple terms.

结论:

Use const When You Can

 

There are three strong reasons to declare reference arguments as references to constant data:

  • Using const protects you against programming errors that inadvertently alter data.

  • Using const allows a function to process both const and non-const actual arguments, while a function omitting const in the prototype only can accept non-const data.

  • Using a const reference allows the function to generate and use a temporary variable appropriately.

You should declare formal reference arguments as const whenever it's appropriate to do so.

 

8.2.4 将引用用于结构

引用非常适合用于结构和类。也主要为了结构和类而产生的


//strtref.cpp --using structure references
#include <iostream>
using namespace std;
struct sysop
{
char name[26];
char quote[64];
int used;
};
sysop & use (sysop &sysopref);// function with a reference return type
int main()
{//NOTE: some implementations require using the keyword static
//in the two structure declarations to enable initialization
sysop looper=
{
"Rick/"Fortran/"Looper",
"I'm a goto kind of guy.",
0
};
use(looper);//looper is type sysop
cout<<looper.used<<" use(s)/n";
use(use(looper));//use(looper) is type sysop
cout<<looper.used<<" use(s)/n";

sysop morf=
{
"Polly Morf",
"Polly's not a hacker.",
0
};
use(looper)=morf; //can assign to function
cout<<looper.name<<"says:/n"<<looper.quote<<endl;
return 0;
}
//use() returns the refetence passed to it
sysop & use(sysop &sysopref)
{
cout<<sysopref.name<<" says:/n";
cout<<sysopref.quote<<endl;
sysopref.used++;
return sysopref;
}

记住:

A function that returns a reference is actually an alias for the referred-to variable

use(looper)=morf;

相对于 looper = morf;

use(looper) = morf;  // return value a reference to looper 

is equivalent to the following:

use(looper); looper = morf;
记住:
 You can assign a value (including a structure or a class object) to a C++ function only if 
the function returns a reference to a variable or, more generally, to a data object. 
In that case, the value is assigned to the referred-to variable or data object.

返回引用或指针时需要考虑的问题

When a function returns a reference or a pointer to a data object, that object had better continue to exist once the function terminates. The simplest way to do that is to have the function return a reference or pointer that was passed to it as an argument. That way, the reference or pointer already refers to something in the calling program. The use() function in Listing 8.6 uses this technique。

!如何使用引用参数!

There are two main reasons for using reference arguments:

  • To allow you to alter a data object in the calling function

  • To speed up a program by passing a reference instead of an entire data object

The second reason is most important for larger data objects, such as structures and class objects. These two reasons are the same reasons one might have for using a pointer argument. This makes sense, for reference arguments are really just a different interface for pointer-based code. So, when should you use a reference? Use a pointer? Pass by value? Here are some guidelines.

A function uses passed data without modifying it:

  • If the data object is small, such as a built-in data type or a small structure, pass it by value.

  • If the data object is an array, use a pointer because that's your only choice. Make the pointer a pointer to const.

  • If the data object is a good-sized structure, use a const pointer or a const reference to increase program efficiency. You save the time and space needed to copy a structure or a class design. Make the pointer or reference const.

  • If the data object is a class object, use a const reference. The semantics of class design often require using a reference, which is the main reason why C++ added this feature. Thus, the standard way to pass class object arguments is by reference.

A function modifies data in the calling function:

  • If the data object is a built-in data type, use a pointer. If you spot code like fixit(&x), where x is an int, it's pretty clear that this function intends to modify x.

  • If the data object is an array, use your only choice, a pointer.

  • If the data object is a structure, use a reference or a pointer.

  • If the data object is a class object, use a reference.p218

8.3默认参数

默认参数指的是当函数调用中省略了实参时,自动使用的一个值。

如何设置默认值?
    通过函数原型从右到左的设置默认值。而实参则按从左到右的顺序依次传递给相应的形参

8.4函数重载(多态)

8.5函数模版

函数模版是通用的函数描述,也就是说,它们使用通用类型来定义函数,其中的通用类型可用具体的类型(如int或double)替换,通过将类型作为参数传递给模版。可是编译器生成该类型的函数

提示:

   如果需要多个将同一种算法用于不同类型的函数,请使用模版,如果不考虑向后兼容性的问题,并愿意键入较长的单词,则声明类型参数的时候,应使用关键字typename而不使用class.

8.5.1重载的模版

并非所有的类型都使用相同的算法,为满足这种需要,可以像重载常规函数定义那样重载模版定义。和常规重载一样,被定义的模版的函数特征标必须不同

8.5.2显示具体化

C++标准选择了下面的方法:

  1. 对于给定的函数名,可以有非模版函数,模版函数和显式化模版函数。

  2. 显式具体化的原型和定义应以template<>打头,并通过名称来指出类型

  3. 具体化将覆盖常规模版,而非模版函数将覆盖具体化和常规类型

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值