C++ Primer Plus 第8章

这篇具有很好参考价值的文章主要介绍了C++ Primer Plus 第8章。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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 ‘int14 |  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)

#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模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++ Primer Plus第五章编程练习答案

    答案仅供参考,实际运行效果取决于运行平台和运行软件 1.编写一个要求用户输入两个整数的程序。该程序将计算并输出这两个整数之间包括这两个整数)所有整数的和。这里假设先输入较小的整数。例如,如果用户输入的是2和则程序将出29之间所有整数的和为44 2.使用array对

    2024年02月09日
    浏览(49)
  • C++ primer plus第七章编程练习答案

    1.编写一个程序,不断要求用户输入两个数,直到其中的一个为 0。对于每两个数,程序将使用一个南数来计算它们的调和平均数,并将结果返回给 main(),而后者将报告结果。调和平均数指的是倒数平均值的倒数,计算公式如下: 调和平均数=2.0*xy/(x + y) 2.编写一个程序,要求用

    2024年02月10日
    浏览(37)
  • C++ Primer Plus第二章编程练习答案

    答案仅供参考,实际运行效果取决于运行平台和运行软件 1.编写一个C++程序,它显示您的姓名和地址。 2.编写一个C程序它要求用户输入一个以 long 为单位的距离,然后将它转换为码(- ng等于220码) 3.编写1个C++程序它使用3个用户定义的函数(括mai()),并生成下面的输出Three blind

    2024年02月09日
    浏览(52)
  • 【CPP_Primer_Plus】C++ IDE推荐

    C++编译器推荐 windows 推荐 Resharper++插件 vcpkg 功能介绍 编辑器 Visual Studio 的编辑器具有出色的代码补全功能、语法突出显示、快速信息提示、附带代码修复建议的错误和警告。 IntelliSense 比 IntelliCode(内置于编辑器中的 AI 工具) 调试器 顶部的绿色运行按钮可启动调试程序。

    2024年02月09日
    浏览(43)
  • C++ Primer Plus笔记: 2023.06.05 AND 2023.06.06

    1.在C++的赋值语句: 赋值将从右向左进行,首先,88被赋值给steinway,然后,steinway的值(现在是88)被赋给baldwin,然后baldwin的值88被赋给yamaha。 2.类与对象: ** 类是用户定义的一种数据类型。要定义类,需要描述它能够表示什么信息和可对数据执行哪些操作,类之于对象就像

    2024年02月08日
    浏览(40)
  • 《C++ Primer Plus》学习笔记——第5章 循环和文本输入

    C++中支持三种循环,for循环、while循环和do while循环。 for循环遍历字符串输出 输出 这里的++i通常也有人写常i++,有前缀和后缀的区别。从语义上来说,二者都是对i进行自增。但是从效率上来说,可能存在差异。通常i++会将i复制一个副本,然后加一,然后再写回,而++i则是直

    2024年02月09日
    浏览(40)
  • C++ Primer Plus 第6版 读书笔记(8)第 8章 函数探幽

    本章内容包括: 通过第 7 章,您了解到很多有关 C++函数的知识,但需要学习的知识还很多。C++还提供许多新的函 数特性,使之有别于 C 语言。新特性包括内联函数、按引用传递变量、默认的参数值、函数重载(多态) 以及模板函数。 本章介绍的 C++在 C 语言基础上新增的特

    2024年02月15日
    浏览(38)
  • C++primer plus习题+答案

    1.什么是类 类是用户定义的类型的定义。类声明指定了数据将如何存储,同时指定了用来访问和操纵这些数据的方法(类成员函数) 2.类如何实现抽象,封装和数据隐藏 类表示人们可以类方法的公有接口对类对象执行的操作,这是抽象,类的数据成员可以是私有的(默认值)

    2024年02月07日
    浏览(40)
  • C++primer plus 习题+答案

    1.哪种函数适合定义为内联函数? 解释:                 一般来说,调用一个函数流程为:当前调用命令的地址被保存下来,程序将跳转到所调用的函数并执行该函数,最后跳转回之前所保存的命令地址。         对于经常需要调用的小函数来说,这大大降低了程序

    2024年02月06日
    浏览(28)
  • 初识C语言 ——“C Primer Plus”

    各位CSDN的uu们你们好呀,今天,小雅兰的内容是读一本好书,这一本书的名字就叫做《C Primer Plus》,那么,又回到了我们的初识C语言阶段啦,保证零基础都能看懂噢,下面,让我们进入C语言的世界吧 C语言的起源 选择C语言的理由 C语言的应用范围 计算机能做什么 高级计算

    2023年04月15日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包