内联函数的运行速度比常规函数稍快,但代价是需要占用更多内存。
要使用这项特性,必须采取下述措施之一:
// 内联函数,按值传递
#include
using namespace std;
inline double square(double x) {return x*x;}
int main(void)
{
double a;
cout << "enter a double number:";
cin >> a;
cout << "a = " << a << ", a square = " << square(a) << endl;
cout << "square(2.1 + 1.9) = " << square(2.1 + 1.9) << endl; // 16
return 0;
}
int rats;
int & rodents = rats; // makes rodents an alias for rats
// 引用变量
#include
using namespace std;
int main(void)
{
int a = 10;
int & b = a; // 引用变量,必须在声明引用时将其初始化
int * pa;
pa = &a; // 指针变量,可以先声明,再赋值。或者 int * pa = &a;
int * const pr = &a; // const指针变量,必须在声明引用时将其初始化。b相当于*pr
cout << "a = " << a << ", b = " << b << ", *pa = " << *pa << endl;
cout << "&a = " << &a << ", &b = " << &b << ", pa = " << pa << endl;
a++;
cout << "a = " << a << ", b = " << b << ", *pa = " << *pa << endl;
cout << "&a = " << &a << ", &b = " << &b << ", pa = " << pa << endl;
b++;
cout << "a = " << a << ", b = " << b << ", *pa = " << *pa << endl;
cout << "&a = " << &a << ", &b = " << &b << ", pa = " << pa << endl;
return 0;
}
out:
a = 10, b = 10, *pa = 10
&a = 0xf091ff614, &b = 0xf091ff614, pa = 0xf091ff614
a = 11, b = 11, *pa = 11
&a = 0xf091ff614, &b = 0xf091ff614, pa = 0xf091ff614
a = 12, b = 12, *pa = 12
&a = 0xf091ff614, &b = 0xf091ff614, pa = 0xf091ff614
可以通过初始化声明来设置引用,但不能通过赋值来设置。
int rats = 101;
int * pt = &rats;
int & rodents = *pt; // 将rodents初始化为*pt使得rodents指向rats。
int bunnies = 50;
pt = &bunnies; // 将pt改为指向bunnies,此时rodents引用的还是rats。
按引用传递允许被调用的函数能够访问调用函数中的变量。
按指针传递、按引用传递、按值传递,外在区别是声明函数参数的方式不同:
void swapp(int * p, int * q); // 按指针传递,调用函数时传递的是变量地址
void swapr(int & a, int & b); // 按引用传递,调用函数时传递的是变量本身
void swapv(int a, int b); // 按值传递,调用函数时传递的是变量副本
如果程序员的意图是让函数使用传递给它的信息,而不对这些信息进行修改,同时又想使用引用,则应使用常量引用。
double refcube(const double &ra);
传递引用的限制更严格。毕竟,如果ra是一个变量的别名,则实参应是该变量,不能是一个表达式或实数。
对于形参为const引用的C++函数,如果实参不匹配,则其行为类似于按值传递,为确保原始数据不被修改,将使用临时变量来存储值。
如果引用参数是const,则编译器将在下面两种情况下生成临时变量:
如果函数调用的参数不是左值或与相应的const引用参数的类型不匹配,则C++将创建类型正确的匿名变量,将函数调用的参数的值传递给该匿名变量,并让参数来引用该变量。
左值是什么呢?
左值参数是可被引用的数据对象,例如,变量、数 组元素、结构成员、引用和解除引用的指针都是左值。非左值包括字面 常量(用引号括起的字符串除外,它们由其地址表示)和包含多项的表 达式。在C语言中,左值最初指的是可出现在赋值语句左边的实体,但 这是引入关键字const之前的情况。现在,常规变量和const变量都可视 为左值,因为可通过地址访问它们。但常规变量属于可修改的左值,而 const变量属于不可修改的左值。
应尽可能将引用形参声明为const:
使用结构引用参数的方式与使用基本变量引用相同,只需在声明结构参数时使用引用运算符&即可。
struct free_throws
{
std::string name;
int made;
int attempts;
float percent;
};
free_throws one = {"Ifelsa Branch", 13, 14}; // 结构初始化时,如果指定的初始值比成员少,余下的成员(这里只有percent)将被设置为零。
free_throws two, three, four, five, dup;
void set_pc(free_throws & ft); // 在函数中将指向该结构的引用作为参数
void display(const free_throws & ft); // 不希望函数修改传入的结构,可使用const
free_throws & accumulate(free_throws & target, const free_throws & source); // 返回也是引用,返回引用的函数实际上是被引用的变量的别名。
accumulate(dup,five) = four; // 首先将five的数据添加到dup中,再使用four的内容覆盖dup的内容。
// 假设您要使用引用返回值,但又不允许执行像给accumulate()赋值 这样的操作,只需将返回类型声明为const引用:
const free_throws & accumulate(free_throws & target, const free_throws & source);
display(accumulate(team, two));
为何要返回引用?
double m = sqrt(16.0);
在第一条语句中,值4.0被复制到一个临时位置,然后被复制给m。cout << sqrt(25.0);
在第二条语句中,值5.0被复制到一个临时位置,然后被传递给cout。dup = accumulate(team,five);
如果accumulate()返回一个结构,而不是指向结构的引用,将把整 个结构复制到一个临时位置,再将这个拷贝复制给dup。但在返回值为引用时,将直接把team复制到dup,其效率更高。返回引用时最重要的一点是,应避免返回函数终止时不再存在的内存单元引用。 为避免这种问题,最简单的方法是,返回一个作为参数传递给函数的引用。作为参数的引用将指向调用函数使用的数据,因此返回的引用也将指向这些数据。
如果形参类型为const string &,在调用函数时,使用的实参可以是 string对象或C-风格字符串,如用引号括起的字符串字面量、以空字符结尾的char数组或指向 char的指针变量。
string input = "happy";
string version1(const string & s1, const string & s2)
{
string temp;
temp = s2 + s1 + s2;
return temp;
}
// temp是一个新的string对象,只在函数version1( )中有效,该函数执行完毕后,它将不再存在。因此,返回指向temp的引用不可行。
// 该函数的返回类型为string,这意味着temp的内容将被复制到一个临时存储单元中,
// 然后在main( )中,该存储单元的内容被复制到一个名为 result 的string中:
string result = version1(input, "***"); // 实参(input和“***”)的类型分别是string和const char *。
version1()函数实参和形参类型不一致但是程序可以运行的原因:
使得能够将特性从一个类传递给另一个类的语言特性被称为继承。
ostream是基类(因为ofstream是建立在它的基础之上的),而ofstream是派生类 (因为它是从ostream派生而来的)。
ostream中的格式化方法:
setf(ios_base::fixed); // 将对象置于使用定点表示法的模式;
setf(ios_base::showpoint); // 将对象置于显示小数点的模式,即使小数部分为零。
// 通过调用同一个函数(只有函数调用参数不同)将数据写入文件和显示到屏幕上
// 该程序要求用户输入望远镜物镜和一些目镜的焦距,然后计算并显示每个目镜的放大倍数。
// 放大倍数等于物镜的焦距除以目镜的焦距,因此计算起来很简单。
#include
#include
#include
using namespace std;
void file_it(ostream & os, double fo, const double fe[],int n);
const int LIMIT = 5;
int main(void)
{
ofstream fout;
const char * fn = "ep-data.txt";
fout.open(fn);
if (!fout.is_open())
{
cout << "Can't open " << fn << ". Bye.\n";
exit(EXIT_FAILURE);
}
double objective;
cout << "Enter the focal length of your "
"telescope objective in mm: ";
cin >> objective;
double eps[LIMIT];
cout << "Enter the focal lengths, in mm, of " << LIMIT
<< " eyepieces:\n";
for (int i = 0; i < LIMIT; i++)
{
cout << "Eyepiece #" << i + 1 << ": ";
cin >> eps[i];
}
file_it(fout, objective, eps, LIMIT); // 将目镜数据写入到文件ep-data.txt中:
file_it(cout, objective, eps, LIMIT); // 将同样的信息以同样的格式显示到屏幕上:
cout << "Done\n";
return 0;
}
// 参数os(其类型为ostream &)可以 指向ostream对象(如cout),也可以指向ofstream对象(如fout)
void file_it(ostream & os, double fo, const double fe[],int n)
{
// ios_base::fmtflags是存储这种信息所需的数据类型名称。
// 因此,将返回值赋给initial将存储调用file_it( )之前的格式化设置,
// 然后便可以使用变量initial作为参数来调用setf( ),将所有的格式化设置恢复到原来的值。
// 因此,该函数将对象回到传递给file_it( )之前的状态。
ios_base::fmtflags initial;
initial = os.setf(ios_base::fixed); // save initial formatting state
os.precision(0);
os << "Focal length of objective: " << fo << " mm\n";
os.setf(ios::showpoint);
os.precision(1);
os.width(12); // 这种设置只在显示下一个值时有效
os << "f.l. eyepiece";
os.width(15);
os << "magnification" << endl;
for (int i = 0; i < n; i++)
{
os.width(12);
os << fe[i];
os.width(15);
os << int (fo/fe[i] + 0.5) << endl;
}
os.setf(initial); // restore initial formatting state
}
out:
Focal length of objective: 1800 mm
f.l. eyepiece magnification
1.0 1800
2.0 900
3.0 600
34.0 53
4.0 450
使用引用参数的主要原因有两个:
对于使用传递的值而不作修改的函数:
对于修改调用函数中数据的函数:
char * left(const char * str, int n = 1);
int harpo(int n, int m = 4, int j = 5); // VALID
// int chico(int n, int m = 6, int j); // INVALID
int groucho(int k = 1, int m = 2, int n = 3); // VALID
char * left(const char * str, int n = 1); // 函数原型
char sample[10];
char * ps = left(sample, 4); // 函数调用
char * pa = left(sample); // 函数调用,此时默认n=1
char * left(const char * str, int n){...} // 函数定义
// 不同引用类型的重载:
double x = 55.5;
const double y = 32.0;
stove(x); // calls stove(double &)
stove(y); // calls stove(const double &)
stove(x+y); // calls stove(double &&)
// 如果没有定义函数stove(double &&),stove(x+y)将调用函数stove(const double &)。
// 函数重载 和 默认参数 的使用
// 由于新left( )的特征标不同于旧的left( ),因此可以在同一个程序中使用这两个函数。
#include
using namespace std;
unsigned long left(unsigned long num, unsigned ct = 1);
char * left(const char * str, int n = 1);
int main(void)
{
char * trip = "Hawaii!!"; // test value
unsigned long n = 12345678; // test value
cout << "n = " << n << ", trip = " << trip << endl;
cout << "left(n) = " << left(n) << endl; // 默认第二个参数为1
cout << "left(n,3) = " << left(n, 3) << endl; // 自定义第二个参数为3
char * temp;
temp = left(trip,5);
cout << "left(trip,5) = " << temp << endl;
delete [] temp; // point to temporary storage
return 0;
}
// This function returns the first ct digits of the number num.
unsigned long left(unsigned long num, unsigned ct)
{
unsigned digits = 1;
unsigned long n = num;
if (ct == 0 || num == 0)
return 0; // return 0 if no digits
while (n /= 10)
digits++;
if (digits > ct)
{
ct = digits - ct;
while (ct--)
num /= 10;
return num; // return left ct digits
}
else // if ct >= number of digits
return num; // return the whole number
}
// This function returns a pointer to a new string
// consisting of the first n characters in the str string.
char * left(const char * str, int n)
{
if(n < 0)
n = 0;
char * p = new char[n+1];
int i;
for (i = 0; i < n && str[i]; i++)
p[i] = str[i]; // copy characters
while (i <= n)
p[i++] = '\0'; // set rest of string to '\0'
return p;
}
out:
n = 12345678, trip = Hawaii!!
left(n) = 1
left(n,3) = 123
left(trip,5) = Hawai
名称修饰?
对原始名称进行的表面看来无意义的修饰(或矫正,因人而异)将对参数数目和类型进行编码。添加的一组符号随函数特征标而异,而修饰时使用的约定随编译器而异。
有了名称修饰,C++可以准确的跟踪每一个重载函数。
long MyFunctionFoo(int, float);
内部表示为:?MyFunctionFoo@@YAXH
函数模板是通用的函数描述,也就是说,它们使用泛型来定义函数,其中的泛型可用具体的类型(如int或double)替换。通过将类型作为参数传递给模板,可使编译器生成该类型的函数。
template <typename AnyType> // 第一行指出,要建立一个模板,并将类型命名为AnyType。
// 关键字 template 和 typename 是必需的,除非可以使用关键字class代替typename。另外,必须使用尖括号。类型名可以任意选择。
void Swap(AnyType &a, AnyType &b)
{
AnyType temp;
temp = a;
a = b;
b = temp;
}
// 函数模板的定义和使用
#include
// function template prototype,这两个函数模板相当于函数重载,函数名字相同,参数即类型不同
template <typename T> // or class T
void Swap(T &a, T &b);
template <typename T> // new template
void Swap(T *a, T *b, int n);
int main()
{
using namespace std;
int i = 10;
int j = 20;
cout << "i, j = " << i << ", " << j << ".\n";
cout << "Using compiler-generated int swapper:\n";
Swap(i,j); // generates void Swap(int &, int &)
cout << "Now i, j = " << i << ", " << j << ".\n";
double x = 24.5;
double y = 81.7;
cout << "x, y = " << x << ", " << y << ".\n";
cout << "Using compiler-generated double swapper:\n";
Swap(x,y); // generates void Swap(double &, double &)
cout << "Now x, y = " << x << ", " << y << ".\n";
return 0;
}
// function template definition
template <typename T> // or class T
void Swap(T &a, T &b)
{
T temp; // temp a variable of type T
temp = a;
a = b;
b = temp;
}
out:
i, j = 10, 20.
Using compiler-generated int swapper:
Now i, j = 20, 10.
x, y = 24.5, 81.7.
Using compiler-generated double swapper:
Now x, y = 81.7, 24.5.
为特定类型提供具体化的模板定义,即具体化函数定义——称为显式具体化(explicit specialization),其中包含所需的代码。
template<>
打头,并通过名称来指出类型。// 下面是用于交换job结构的非模板函数、模板函数和具体化的原型:
struct job
{
char name[40];
double salary;
int floor;
};
void Swap(job &, job &); // non template function prototype
template <typename T>
void Swap(T &, T &); // template prototype
template <> void Swap<job>(job &, job &); // explicit specialization for the job type
在下面的代码中,第一次调用Swap( )时使用通用版本,隐式实例化。而第二次调用使用基于job类型的显式具体化版本。
struct job
{
char name[40];
double salary;
int floor;
};
template <class T> // template
void Swap(T &, T &);
template <> void Swap<job>(job &, job &); // explicit specialization for the job type
int main()
{
double u, v;
...
Swap(u,v); // 隐式实例化:第一次调用Swap( )时使用通用版本
job a, b;
...
Swap(a,b); // 显示具体化:第二次调用使用基于job类型的显式具体化版本 void Swap(job &, job &)
}
template <class T>
void Swap (T &, T &); // 模板原型
int i, j;
Swap(i, j); // 隐式实例化
// 函数调用Swap(i, j)导致编译器生成Swap( )的一个实例,该实例使用int类型。
// 模板并非函数定义,但使用int的模板实例是函数定义。
// 因为编译器之所以知道需要进行定义,是由于程序调用Swap( )函数时提供了int参数。
template void Swap<int>(int, int); // explicit instantiation
template <> void Swap<int>(int &, int &); // explicit specialization
template <> void Swap(int &, int &); // explicit specialization
...
template <class T>
void Swap (T &, T &); // template prototype
template <> void Swap<job>(job &, job &); // explicit specialization for job
int main(void)
{
...
template void Swap<char>(char &, char &); // 显式实例化 for char
short a, b;
...
Swap(a,b); // 隐式实例化
job n, m;
...
Swap(n, m); // 显式具体化:使用为job类型提供的独立定义
char g, h;
...
Swap(g, h); // 使用处理显式实例化时生成的模板具体化
...
}
从最佳到最差的顺序如下所述:
struct blot {int a; char b[10];};
blot ink = {25, "spots"};
...
recycle(ink);
// 下面的原型都是完全匹配的:
void recycle(blot); // #1 blot-to-blot
void recycle(const blot); // #2 blot-to-(const blot)
void recycle(blot &); // #3 blot-to-(blot &)
void recycle(const blot &); // #4 blot-to-(const blot &)
decltype(expression) var;
// make var the same type as expression
decltype(x + y) xpy; // make xpy the same type as x + y
xpy = x + y;
// 合并为一条语句:
decltype(x + y) xpy = x + y;
// 第一步:如果expression是一个没有用括号括起的标识符,则var的类型与该标识符的类型相同,包括const等限定符:
double x = 5.5;
double y = 7.9;
double &rx = x;
const double * pd;
decltype(x) w; // w is type double
decltype(rx) u = y; // u is type double &
decltype(pd) v; // v is type const double *
// 第二步:如果expression是一个函数调用,则var的类型与函数的返回类型相同:
long indeed(int);
decltype (indeed(3)) m; // m is type long
// 第三步:如果expression是一个左值(是用括号括起的标识符),则var为指向其类型的引用。
double xx = 4.4;
decltype((xx)) r2 = xx; // r2 is double &
decltype(xx) w = xx; // w is double (Stage 1 match)
// 第四步:如果前面的条件都不满足,则var的类型与expression的类型相同:
int j = 3;
int &k = j
int &n = j;
decltype(j+6) i1; // i1 type int
decltype(100L) i2; // i2 type long
decltype(k+n) i3; // i3 type int; 虽然k和n都是引用,但表达式k+n不是引用;它是两个int 的和,因此类型为int。
C++11后置返回类型:
// 无法预先知道将x和y相加得到的类型。
// 此时还未声明参数x和y,它们不在作用域内(编译器看不到它们,也无法使用它们)。
// 必须在声明参数后使用decltype。
template<class T1, class T2>
auto gt(T1 x, T2 y) -> decltype(x + y) // decltype在参数声明后面,因此x和y位于作用域内
{
...
return x + y;
}
void song(const char * name, int times);
void song(const char * name = "O. My Papa", int times = 1);
void iquote(int n){std::cout << "\"" << n << "\"\n";}
void iquote(double n){std::cout << "\"" << n << "\"\n";}
void iquote(string n){std::cout << "\"" << n << "\"\n";}
double mass(double density, double volume = 1.0);
double mass(double density, double volume);
和double mass(double density);
void repeat(int n, const char *str);
和void repeat(const char *str);
template <typename AnyType>
AnyType Max(AnyType x, AnyType y)
{
if (x > y)
return x;
else
return y;
// return x > y ? x : y;
}
struct box
{
char maker[40];
float height;
float width;
float length;
float volume;
};
template <typename AnyType>
AnyType Max(AnyType x, AnyType y)
{
return x > y ? x : y;
}
template <> box Max<box>(box b1, box b2)
{
return b1.volume > b2.volume ? b1 : b2;
}
int g(int x);
...
float m = 5.5f;
float & rm = m;
decltype(m) v1 = m; // float, v1由m决定
decltype(rm) v2 = m; // float &
decltype((m)) v3 = m; // float &
decltype (g(100)) v4; // int
decltype (2.0 * m) v5; // double, 2.0是double
// 1.编写通常接受一个参数(字符串的地址),并打印该字符串的函数。
// 然而,如果提供了第二个参数(int类型),且该参数不为0,
// 则该函数打印字符串的次数将为该函数被调用的次数
// (注意,字符串的打印次数不等于第二个参数的值,而等于函数被调用的次数)。
#include
using namespace std;
void show(const char *str, int n = 0);
int main(void)
{
show("chai");
show("come on!");
show("I love you.", 8);
return 0;
}
void show(const char *str, int n)
{
static int count = 0; // 调用多次该函数,只初始化一次
count++;
if (n == 0)
cout << str << endl;
else
{
for (int i=0; i<count; i++)
cout << str << endl;
}
}
// 2.CandyBar结构包含3个成员。
// 第一个成员存储candy bar的品牌名称;第二个成员存储candy bar的重量(可能有小数);第三个成员存储 candy bar的热量(整数)。
// 请编写一个程序,它使用一个这样的函数,即将CandyBar的引用、char指针、double和int作为参数,并用最后3个值设置相应的结构成员。
// 最后3个参数的默认值分别为“Millennium Munch”、2.85和350。
// 另外,该程序还包含一个以CandyBar的引用为参数,并显示结构内容的函数。
// 请尽可能使用const。
#include
#include
using namespace std;
struct CandyBar
{
char name[20];
float weight;
int heat;
};
void set_value(CandyBar & aaa, const char *str = "Millennium Munch", const double w = 2.85, const int h = 350);
void show(const CandyBar & aaa);
int main(void)
{
CandyBar aaaaa;
set_value(aaaaa);
show(aaaaa);
return 0;
}
void set_value(CandyBar & aaa, const char *str, const double w, const int h)
{
strcpy(aaa.name, str); // 这里使用字符串拷贝函数
aaa.weight = w;
aaa.heat = h;
}
void show(const CandyBar & aaa)
{
cout << aaa.name << endl;
cout << aaa.weight << endl;
cout << aaa.heat << endl;
}
// 3.编写一个函数,它接受一个指向string对象的引用作为参数,并将该string对象的内容转换为大写,为此可使用表6.4描述的函数toupper( )。
// 然后编写一个程序,它通过使用一个循环让您能够用不同的输入来测试这个函数,该程序的运行情况如下:
#include
#include
#include
using namespace std;
void transform(string & str);
int main(void)
{
cout << "please enter a string (q to quit):";
string str;
getline(cin, str); // 这里注意
while (str != "q")
{
transform(str);
cout << str << endl;
cout << "please enter a string (q to quit):";
getline(cin, str);
}
cout << "Bye" << endl;
return 0;
}
void transform(string & str)
{
for (int i=0; i < str.size(); i++)
str[i] = toupper(str[i]); // 使用引用参数,这里直接改变它本身,不需要再返回
}
// 4.请提供其中描述的函数和原型,从而完成该程序。
// 注意,应有两个 show( )函数,每个都使用默认参数。请尽可能使用cosnt参数。
// set( )使用 new分配足够的空间来存储指定的字符串。这里使用的技术与设计和实现类时使用的相似。
#include
using namespace std;
#include // for strlen(), strcpy()
struct stringy
{
char * str; // points to a string
int ct; // length of string (not counting '\0')
};
// prototypes for set(), show(), and show() go here
void set(stringy & str, const char *source);
void show(const stringy & str, int n = 1);
void show(const char *str, int n = 1);
int main()
{
stringy beany;
char testing[] = "Reality isn't what it used to be.";
set(beany, testing); // first argument is a reference,
// allocates space to hold copy of testing,
// sets str member of beany to point to the
// new block, copies testing to new block,
// and sets ct member of beany
show(beany); // prints member string once
show(beany, 2); // prints member string twice
testing[0] = 'D';
testing[1] = 'u';
show(testing); // prints testing string once
show(testing, 3); // prints testing string thrice
show("Done!");
delete [] beany.str;
return 0;
}
void set(stringy & str, const char *source)
{
str.ct = strlen(source) + 1;
str.str = new char[str.ct];
strcpy(str.str, source);
}
void show(const stringy & str, int n)
{
for (int i=0; i<n; i++)
cout << str.str << endl;
}
void show(const char *str, int n)
{
for (int i=0; i<n; i++)
cout << str << endl;
}
// 6.编写模板函数maxn( ),它将由一个T类型元素组成的数组和一个表示数组元素数目的整数作为参数,并返回数组中最大的元素。
// 在程序对它进行测试,该程序使用一个包含6个int元素的数组和一个包含4个 double元素的数组来调用该函数。
// 程序还包含一个具体化,它将char指针数组和数组中的指针数量作为参数,并返回最长的字符串的地址。
// 如果有多个这样的字符串,则返回其中第一个字符串的地址。
// 使用由5个字符串指针组成的数组来测试该具体化。
#include
#include
using namespace std;
template <typename T>
T maxn(T arr[], int n); // 模板函数
template <> string maxn<string>(string str[], int n);
int main(void)
{
int arr1[6] = {0, 2, 4, 6, 2, 1};
double arr2[4] = {3.14, 3.1415, 2.1, 0.5};
cout << "int arr1[6] max : " << maxn(arr1, 6) << endl;
cout << "double arr2[4] max : " << maxn(arr2, 4) << endl;
string str[5] = {"hello world!", "chai", "mian", "i love you", "thank you"};
cout << "char *str[5] max : " << maxn(str, 5) << endl;
return 0;
}
template <typename T>
T maxn(T arr[], int n)
{
T temp = arr[0];
for (int i=0; i<n; i++)
if (arr[i] > temp)
temp = arr[i];
return temp;
}
template <>
string maxn<string>(string str[], int n) // 函数模板具体化
{
int temp = 0;
for (int i=0; i<n; i++)
{
if (str[temp].size() < str[i].size())
temp = i;
}
return str[temp];
}
// 7.修改程序清单 8.14,使其使用两个名为 SumArray()的模板函数来返回数组元素的总和,而不是显示数组的内容。
// 程序应显示thing的总和以及所有debt的总和。
#include
template <typename T> // template A
void ShowArray(T arr[], int n);
template <typename T> // template B
void ShowArray(T * arr[], int n);
template <typename T>
T SumArray(T arr[], int n);
template <typename T>
T SumArray(T * arr[], int n);
struct debts
{
char name[50];
double amount;
};
int main()
{
using namespace std;
int things[6] = {13, 31, 103, 301, 310, 130};
struct debts mr_E[3] =
{
{"Ima Wolfe", 2400.0},
{"Ura Foxe", 1300.0},
{"Iby Stout", 1800.0}
};
double * pd[3]; // set pointers to the amount members of the structures in mr_E
for (int i = 0; i < 3; i++)
pd[i] = &mr_E[i].amount;
cout << "Listing Mr. E's counts of things:\n";
ShowArray(things, 6); // uses template A
cout << "\nListing Mr. E's debts:\n";
ShowArray(pd, 3); // uses template B (more specialized)
cout << "\nThe sum of things : " << SumArray(things, 6) << endl;
cout << "\nThe sum of debts : " << SumArray(pd, 3) << endl;
return 0;
}
template <typename T>
void ShowArray(T arr[], int n)
{
using namespace std;
cout << "template A\n";
for (int i = 0; i < n; i++)
cout << arr[i] << ' ';
cout << endl;
}
template <typename T>
void ShowArray(T * arr[], int n)
{
using namespace std;
cout << "template B\n";
for (int i = 0; i < n; i++)
cout << *arr[i] << ' ';
cout << endl;
}
template <typename T>
T SumArray(T arr[], int n)
{
T sum = 0;
for (int i=0; i<n; i++)
sum += arr[i];
return sum;
}
template <typename T>
T SumArray(T * arr[], int n)
{
T sum = 0;
for (int i=0; i<n; i++)
sum += *arr[i];
return sum;
}