1.内联函数的运行速度比常规函数稍快,但代价是需要占用更多内存。如果程序在10个不同的地方调用同一个内联函数,则程序将包含该函数代码的10个副本。
2.注意,内联函数不能递归。
3.在声明引用时必须将其初始化,否则就会出现类似以下的报错:
error: ‘rodents’ declared as reference but not initialized
7 | int & rodents ;
| ^~~~~~~
4.引用一旦和某个变量关联起来, 就将一直效忠于该变量,以下面的程序为例:
#include <iostream>
using namespace std ;
int main()
{
int rats = 101 ;
int & rodents = rats ;
cout << "rats = " << rats ;
cout << ", rodents = " << rodents << endl ;
cout << "rats address = " << &rats ;
cout << ", rodents address = " << &rodents << endl ;
int bunnies = 50 ;
rodents = bunnies ;
cout << "bunnies = " << bunnies ;
cout << ", rats = " << rats ;
cout << ", rodents = " << rodents << endl ;
cout << "bunnies address = " << &bunnies ;
cout << ", rodents address = " << &rodents ;
cout << ", rats address = " << &rats << endl ;
return 0 ;
}
运行结果如下:
rats = 101, rodents = 101
rats address = 0x7ffef13339b8, rodents address = 0x7ffef13339b8
bunnies = 50, rats = 50, rodents = 50
bunnies address = 0x7ffef13339bc, rodents address = 0x7ffef13339b8, rats address = 0x7ffef13339b8
5.如果想在一个自定义函数使用引用,还不想对传递给函数的信息修改,则可以这样:
double refcube(const double &ra)
{
ra *= ra * ra ;
return ra ;
}
因为传递给函数的信息被修改,就报错了:
error: assignment of read-only reference ‘ra’
26 | ra *= ra * ra ;
| ~~~^~~~~~~~~~
6.对于使用引用的自定义函数:
double refcube(double &ra)
{
ra *= ra * ra ;
return ra ;
}
下面这种调用方式是不合适的:
error: cannot bind non-const lvalue reference of type ‘double&’ to an rvalue of type ‘double’
16 | double z = refcube(x + 3.0) ;
| ~~^~~~~
但如果我把函数改称这样,该函数调用就可以了:
double refcube(const double &ra)
{
return ra * ra ;
}
7.重新设定一个函数:
double refcube(const double &ra)
{
return ra * ra * ra ;
}
这三种调用:
double side = 3.0 ;
long edge = 5L ;
double c5 = refcube(edge) ;
double c6 = refcube(7.0) ;
double c7 = refcube(side + 10.0) ;
在这样的情况下,编译器都将生成一个临时匿名变量,并让ra指向它,这些临时变量只在函数调用期间存在,此后编译器可以随意将其删除。
8.在编写自定义函数时若要返回引用,应该避免返回函数终止时不再存在的内存单元引用,比如下列函数就存在问题:
const free_throws & clone2(free_throws & ft)
{
free_throws newguy ;
newguy = ft ;
return newguy ;
}
启动编译后导致了如下的报错:
strtref.cpp: In function ‘const free_throws& clone2(free_throws&)’:
strtref.cpp:81:9: warning: reference to local variable ‘newguy’ returned [-Wreturn-local-addr]
81 | return newguy ;
| ^~~~~~
strtref.cpp:79:14: note: declared here
79 | free_throws newguy ;
| ^~~~~~
9.下面的这个函数指出了什么不能做:
const string & version3(string & s1, const string & s2)
{
string temp ;
temp = s2 + s1 + s2 ;
return temp ;
}
该函数返回一个指向version3( )中声明的变量的引用。这个函数能够通过编译,不过发出了警告:
strquote.cpp: In function ‘const string& version3(std::string&, const string&)’:
strquote.cpp:53:9: warning: reference to local variable ‘temp’ returned [-Wreturn-local-addr]
53 | return temp ;
| ^~~~
strquote.cpp:51:9: note: declared here
51 | string temp ;
| ^~~~
当程序试图执行该函数时就会发生崩溃,问题在于:
result = version3(input, "@@@") ;
程序试图引用已经释放的内存。
10.ofstream对象可以使用ostream类的方法,这使得文件输入/输出的格式与控制台输入/输出方式相同。使得能够将特性从一个类传递给另一个类的语言特性称为继承。简单的说,ostream是基类(因为ofstream是建立在它的基础上的),而ofstream是派生类(因为它是从ostream派生来的)。派生类继承了基类的方法,这意味着ofstream对象可以使用基类的特征,如格式化方法precision( )和setf( )。
基类引用可以指向派生类对象,而无需进行强制类型转换。
11.ostream类中的一些格式化方法:
方法:
setf(ios_base::fixed)
将对象置于使用定点表示法的模式。
方法:
setf(ios::showpoint)
将对象置于显示小数点的模式,即使小数点为0.
方法:
precision( )
指定显示多少位小数(假定对象处于定点模式下)。
方法:
width( )
设置下一次输出操作使用的字段宽度,这种设置只在显示下一值时有效。然后将恢复到默认设置。
方法:
setf( )
返回调用它之前所有有效的格式化设置。ios_base::fmtflags是存储这种信息所需的数据类型名称。因此,将返回值赋给initial将存储调用setf( )之前的格式化设置。
12.对于带参数列表的函数,必须从右向左添加默认值。也就是说,要为某个参数设置默认值,则必须要为它右边的所有参数提供默认值。
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
第二个函数原型是错误的,报错如下:
error: default argument missing for parameter 3 of ‘int chico(int, int, int)’
5 | int chico(int n, int m=6, int j) ;
| ~~~~^
实参按从左到右的顺序依次被赋给相应的形参,而不能跳过任何参数。因此,下面的调用是不可以的:
beeps = harpo(2, ,8) ;
报错如下:
error: expected primary-expression before ‘,’ token
13 | cout << "This is harpo 4: " << harpo(3, ,8) << endl ;
| ^
13.编译器在检查函数特征标时,将把类型引用和类型本身视为同一个特征标。
14.请记住,是特征标,而不是函数类型使得可以对函数进行重载。例如,下面两个声明是互斥的:
long gronk(int n, float m) ;
double gronk(int n, float m) ;
编译时会发生这样的报错:
error: ambiguating new declaration of ‘double gronk(int, float)’
5 | double gronk(int n, float m) ;
| ^~~~~
note: old declaration ‘long int gronk(int, float)’
4 | long gronk(int n, float m) ;
| ^~~~~
error: ambiguating new declaration of ‘double gronk(int, float)’
18 | double gronk(int n, float m)
| ^~~~~
note: old declaration ‘long int gronk(int, float)’
12 | long gronk(int n, float m)
| ^~~~~
因此,C++不允许以这样的方式重载gronk( ) ,返回类型可以不同,但特征标也必须不同。就像这样:
long gronk(int n, float m) ;
double gronk(float n, float m) ;
15.如果有多个原型,则编译器在选择原型时,非模板版本优先于显式具体化和模板版本,而显示具体化优先于使用模板生成的版本。
16.显式实例化:
(1)
#include <iostream>
using namespace std ;
template <class T>
T Add(T a, T b)
{
return a+b ;
}
int main()
{
int m = 6 ;
double x = 10.2 ;
cout << Add<double>(x, m) << endl ;
}
运行起来是没有问题的。结果为16.2。
改称这样:
cout << Add<int>(x, m) << endl ;
也是没有问题的,运行结果为16.
(2)
但是,一旦我们在上述的代码的显式实例化中使用引用,情况就不一样了:
#include <iostream>
using namespace std ;
template <class T>
T Add(T &a, T &b)
{
return a+b ;
}
int main()
{
int m = 6 ;
double x = 10.2 ;
cout << Add<int>(x, m) << endl ;
}
报错如下:
error: cannot bind non-const lvalue reference of type ‘int&’ to an rvalue of type ‘int’
14 | cout << Add<int>(x, m) << endl ;
| ^
note: initializing argument 1 of ‘T Add(T&, T&) [with T = int]’
5 | T Add(T &a, T &b)
| ~~~^
加上const, 有可以通过编译,运行结果为16:
#include <iostream>
using namespace std ;
template <class T>
T Add(const T &a, const T &b)
{
return a+b ;
}
int main()
{
int m = 6 ;
double x = 10.2 ;
cout << Add<int>(x, m) << endl ;
}
17.如果两个完全匹配的函数都是模板函数,则较具体的模板函数优先。例如,这意味着将显式具体化将优先于使用模板隐式生成的具体化。术语“最具体”并不一定意味着显式具体化。而是指编译器推断使用哪种类型时执行的转换最少。
下面的两个模板函数都有错误:
#include <iostream>
using namespace std ;
template <class Type> void recycle(Type t) ;
template <class Type> void recycle(Type * t) ;
struct blot
{
int a ;
char b[10] ;
} ;
int main()
{
blot ink = {25, "spots"} ;
recycle(&ink) ;
}
template <class Type> void recycle(Type t)
{
cout << "This is recycle 1.\n" ;
cout << "a = " << t.a << endl ;
cout << "b[] = " << t.b << endl ;
}
template <class Type> void recycle(Type * t)
{
cout << "This is recycle 2.\n" ;
cout << "a = " << t.a << endl ;
cout << "b[] = " << t.b << endl ;
}
但是编译的报错却是这样的:
test10.cpp: In instantiation of ‘void recycle(Type*) [with Type = blot]’:
test10.cpp:16:14: required from here
test10.cpp:29:22: error: request for member ‘a’ in ‘t’, which is of pointer type ‘blot*’ (maybe you meant to use ‘->’ ?)
29 | cout << "a = " << t.a << endl ;
| ~~^
test10.cpp:30:31: error: request for member ‘b’ in ‘t’, which is of pointer type ‘blot*’ (maybe you meant to use ‘->’ ?)
30 | cout << "b[] = " << t.b << endl ;
| ~~^
两处错误都在第二个模板函数,由此可见第二个模板更具体
18.你没有看错,这个程序也是能正常跑的:
#include <iostream>
using namespace std ;
long ideed(int) ;
int main()
{
double x = 5.5 ;
double y = 7.9 ;
double &rx = x ;
const double * pd ;
decltype(x) w ;
if( typeid(w) == typeid(double) ) cout << "w is double.\n" ;
decltype(rx) u = y ;
if( typeid(u) == typeid(double &) ) cout << "w is double &.\n" ;
decltype(pd) v ;
if( typeid(v) == typeid(const double *) ) cout << "v is const double *.\n" ;
decltype(ideed(3)) m ;
if( typeid(m) == typeid(long) ) cout << "m is long.\n" ;
}
运行结果:
w is double.
w is double &.
v is const double *.
m is long.
事实上在下面这句:
decltype(ideed(3)) m ;
函数ideed( )并没有真的被调用,编译器只不过通过查看函数的原型来知晓其返回类型。
第八章编程题:
(1)
#include <iostream>
using namespace std ;
int times = 0 ;
void PrintString(char * str, int n = 0) ;
int main()
{
PrintString("Hello!") ;
PrintString("Mike John!") ;
PrintString("Opfafaufgueagvure") ;
PrintString("dabwcwjcvrvbevuygeuvruvguevue") ;
PrintString("eqweyqywqyfywqtfywtr") ;
PrintString("Jack London", 9) ;
}
void PrintString(char * str, int n)
{
times ++ ;
if (n >0)
{
for (int i=0; i<times; i++)
cout << str << endl ;
}
else
cout << str << endl ;
}
(2)
#include <iostream>
#include <cstring>
using namespace std ;
const int SIZE = 100 ;
struct CandyBar
{
string brand ;
double weight ;
int calories ;
} ;
void Set_CandyBar(CandyBar &C, double weight = 2.85, int calories = 350, string str = "Millennium Munch") ;
void Set_CandyBar(CandyBar &C, string str = "Millennium Munch", int calories = 350, double weight = 2.85) ;
void Set_CandyBar(CandyBar &C, string str = "Millennium Munch", double weight = 2.85, int calories = 350) ;
void Show_CandyBar(const CandyBar &C) ;
int main()
{
CandyBar C ;
char brandname[SIZE] ;
double w ;
int cal ;
while(1)
{
cout << "Do you want to carry on? [Y/N] " ;
char flag ;
cin >> flag ;
cin.get() ;
if (flag != 'y' && flag != 'Y') break ;
cout << "Please enter the candy's information:\n" ;
cout << "Brand: " ;
cin.getline(brandname, SIZE) ;
cout << "Weight: " ;
if(!(cin >> w))
{
cin.clear() ;
cin.get() ;
}
cout << "Calories: " ;
if(!(cin >> cal))
{
cin.clear() ;
cin.get() ;
}
if (strlen(brandname) == 0 && w && cal)
Set_CandyBar(C, w, cal) ;
else if(strlen(brandname) && !w && cal)
Set_CandyBar(C, brandname, cal) ;
else if(strlen(brandname) && w && !cal)
Set_CandyBar(C, brandname, w) ;
else if(!w && !cal)
{
cout << "Input ERROR !\n" ;
continue ;
}
else Set_CandyBar(C, brandname, w, cal) ;
Show_CandyBar(C) ;
}
}
void Set_CandyBar(CandyBar &C, double weight, int calories, string str)
{
C.brand = str ;
C.weight = weight ;
C.calories = calories ;
}
void Set_CandyBar(CandyBar &C, string str, int calories, double weight)
{
C.brand = str ;
C.weight = weight ;
C.calories = calories ;
}
void Set_CandyBar(CandyBar &C, string str, double weight, int calories)
{
C.brand = str ;
C.weight = weight ;
C.calories = calories ;
}
void Show_CandyBar(const CandyBar &C)
{
cout << "Brand = " << C.brand << ", " << "Weight = "
<< C.weight << ", " << "Calories = " << C.calories
<< endl ;
}
(3)
#include <iostream>
#include <string>
#include <cctype>
using namespace std ;
void Upper(const string & str) ;
int main()
{
string str ;
cout << "Enter a string (q to quit): " ;
while (1)
{
getline(cin, str) ;
if (str == "q") break ;
Upper(str) ;
cout << "Next string (q to quit): " ;
}
}
void Upper(const string & str)
{
for (int i=0; i<str.size(); i++)
cout << char(toupper(str[i])) ;
cout << endl ;
}
(4)
#include <iostream>
#include <cstring>
using namespace std ;
struct stringy
{
char * str ;
int ct ;
} ;
void set(stringy & beany, char testing[]) ;
void show(const stringy & beany, int times = 1) ;
void show(const char testing[], int times = 1) ;
int main()
{
stringy beany ;
char testing[] = "Reality isn't what it uesd to be." ;
set(beany, testing) ;
show(beany) ;
show(beany, 2) ;
testing[0] = 'D' ;
testing[1] = 'u' ;
show(testing) ;
show(testing, 3) ;
show("Done!") ;
delete [] beany.str ;
return 0 ;
}
void set(stringy & beany, char testing[])
{
beany.ct = strlen(testing) ;
beany.str = new char [beany.ct+1] ;
strcpy(beany.str, testing) ;
beany.str[beany.ct] = '\0' ;
}
void show(const stringy & beany, int times)
{
for (int i=0; i<times; i++)
{
cout << "#" << (i+1) <<":\n" ;
cout << "beany.str = " << beany.str << endl ;
cout << "beany.ct = " << beany.ct << endl ;
}
}
void show(const char testing[], int times)
{
for (int i=0; i<times; i++)
{
cout << "#" << (i+1) <<":\n" ;
cout << "testing = " << testing << endl ;
}
}
(5)
#include <iostream>
using namespace std ;
template <class T>
T max5(T a[])
{
T max = a[0] ;
for (int i=1; i<5; i++)
{
if(a[i] > max) max = a[i] ;
}
return max ;
}
int main()
{
int a1[5] = {100, 894, 12, 109, 7} ;
cout << "The max of array a1 = " << max5(a1) << endl ;
double a2[5] = {0.2, 0.9, 0.01, 7.8, 0.05} ;
cout << "The max of array a2 = " << max5(a2) << endl ;
}
(6)文章来源:https://www.toymoban.com/news/detail-632904.html
#include <iostream>
#include <cstring>
using namespace std ;
template <class T>
T maxn(T a[], int n) ;
template <> char* maxn(char* a[], int n) ;
int main()
{
int a[6] = {19, 45, 87, 102, 3, 2} ;
cout << "The maximum of array a = " << maxn(a, 6) << endl ;
double b[4] = {4.5, 5.6, 9.87, 2.34} ;
cout << "The maximum of array b = " << maxn(b, 4) << endl ;
char * c[5] = {"opopopop", "eriwirhierhgiehighei",
"opfw fsksgfdsbdbdbdbdsdbdfbd", "bill Opper", "dfsauy"} ;
cout << "The longest string of c is " << maxn(c, 5) << endl ;
char * d[5] = {"Jack Cheng", "Mike", "Jack Zheng", "Bill", "OPer"} ;
cout << "The longest string of d is " << maxn(d, 5) << endl ;
}
template <class T>
T maxn(T a[], int n)
{
T max = a[0] ;
for (int i=1; i<n; i++)
if (a[i] > max) max = a[i] ;
return max ;
}
template <> char* maxn(char* a[], int n)
{
int length[n] = {0} ;
for (int i=0; i<n; i++)
length[i] = strlen(a[i]) ;
int max = 0 ;
for (int i=1; i<n; i++)
if(length[i] > length[max]) max = i ;
return a[max] ;
}
(7)文章来源地址https://www.toymoban.com/news/detail-632904.html
#include <iostream>
using namespace std ;
template <typename T>
void SumArray(T arr[], int n) ;
template <typename T>
void SumArray(T * arr[], int n) ;
struct debts
{
char name[50] ;
double amount ;
} ;
int main()
{
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] ;
for (int i=0; i<3; i++)
pd[i] = &mr_E[i].amount ;
cout << "The sum of Mr. E's counts of things = " ;
SumArray(things, 6) ;
cout << endl ;
cout << "The sum of Mr. E's debts = " ;
SumArray(pd, 3) ;
cout << endl ;
return 0 ;
}
template <typename T>
void SumArray(T arr[], int n)
{
T total = 0 ;
for (int i=0; i<n; i++)
total += arr[i] ;
cout << total ;
}
template <typename T>
void SumArray(T * arr[], int n)
{
T total = 0 ;
for (int i=0; i<n; i++)
total += *arr[i] ;
cout << total ;
}
到了这里,关于C++ Primer Plus 第8章的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!