C++primer plus编程练习参考答案

目录

第2章 开始学习C++

第3章 处理数据

第4章 复合类型

第5章 循环和关系表达式

第6章 分支语句和逻辑运算符

第7章 函数C++编程模块

第8章 函数探幽

第9章 内存模型和名称空间

第10章 对象和类

第11章 使用类

第12章 类和动态内存分配

第13章 类继承

第14章 C++中的代码重用


第2章 开始学习C++

1.编写一个C++程序,它显示您的姓名和地址。

#include<iostream>
using namespace std;
int main(void)
{
	string name;
	string address;
	cout << "请输入您的姓名:" << endl;
	cin >> name;
	cout << "请输入您的地址:" << endl;
	cin >> address;
	cout << "您的姓名是:" <<name<< endl;
	cout << "您的地址是:" <<address<<endl;
	system("pause");
	return 0;
}


2.编写一个C++程序,它要求用户输入一个以long为单位的距离,然后将它转换为码(一long 等于220码)。

#include <iostream>
using namespace std;
int main(void)
{
	double distence;
	cout << "请输入一个距离(单位:long):" << endl;
	cin >> distence;
	cout << "您输入的距离为 " << distence << " long," << "即 " << 220 * distence << " 码" << endl;
	system("pause");
	return 0;
}

3.编写一个C++程序,它使用3个用户定义的函数(包括main()),并生成下面的输出:

Three blind mice
Three blind mice
See how they run
See how they run

其中一个函数要调用两次,该函数生成前两行,另一个函数也被调用两次,并生成其余的输出

#include <iostream>
using namespace std;
void print1(void)
{
	cout << "Three blind mice" << endl;
}
void print2(void)
{
	cout << "See how they run" << endl;
}
int main(void)
{
	print1();
	print1();

	print2();
	print2();

	system("pause");
	return 0;
}

4.编写一个程序,让用户输入其年龄然后显示该年龄包含多少个月,如下所示:
Enter your age:29

#include <iostream>
using namespace std;

int main(void)
{
	int age;
	cout << "Enter your age:" << endl;
	cin >> age;
	cout << "your age cintains " << age * 12 << "months" << endl;
	system("pause");
	return 0;
}

5."编写”个程序;其中的main()调用一个用户定义的函数(以摄氏温度值为参数,并返回相应的华氏温度值)。该程序按下面的格式要求用户输入摄氏温度值,并显示结果:
please, enter a Celsius value: 20
20 degrees Celsius is 68  degrees Fahrenheit

下面是转换公式:

华氏温度=1.8X 摄氏温度+ 32.0

#include <iostream>
using namespace std;

int main(void)
{
	double value;
	cout << "please, enter a Celsius value :" << endl;
	cin >> value;
	cout << value << " degrees Celsius is " << 1.8 * value + 32.0 << "  degrees Fahrenheit" << endl;


	system("pause");
	return 0;
}

6.编写一个程序,其main( )调用一个用户定义的函数(以光年值为参数,并返回对应天文单位的值)。该程序按下面的格式要求用户输入光年值,并显示结果:
Enter the number of light years: 4.2
4.2 light years = 265608 astronomical units.
天文单位是从地球到太阳的平均距离(约1000000公里或9300000英里),光年是光一年走的距离
(约10万亿公里或6万亿英里) (除太阳外,最近的恒星大约离地球4.2光年)。请使用double类型(参见
程序清单2.4),转换公式为:
1光年=63240天文单位

#include <iostream>
using namespace std;

double convert(double L_Y)
{
	return L_Y * 63240;
}

int main(void)
{
	double L_Y = 0;//光年值
	cout << "Enter the number of light years :";
	cin >> L_Y;
	int ast = convert(L_Y);
	cout << L_Y << " light years = " <<ast << " astronomical units." << endl;
	system("pause");
	return 0;
}

7.编写一个程序,要求用户输入小时数和分钟数。在main( )函数中,将这两个值传递给一个void函
数,后者以下面这样的格式显示这两个值:
Enter the number of hours: 9
Enter the number of minutes: 28
Time: 9:28

#include <iostream>
using namespace std;

void print(int hours, int minutes)
{
	cout <<"Time: "<< hours<<":"<<minutes << endl;
}
int main(void)
{
	int hours = 0;
	int minutes = 0;
	cout << "Enter the number of hours :";
	cin >> hours;
	cout << "Enter the number of minutes :";
	cin >> minutes;

	print(hours, minutes);
	system("pause");
	return 0;
}

第3章 处理数据

1.编写一个小程序,要求用户使用一个整数指出自己的身高(单位为英寸),然后将身高转换为英尺和英寸。该程序使用下划线字符来指示输入位置。另外,使用一个const符号常量来表示转换因子。

#include <iostream>
using namespace std;

int main(void)
{
	//1 英尺=12 英寸
	const int convert_factor = 12;
	int height_inches = 0;
	cout << "Please enter your height (in inches):";
	cin >> height_inches;
	cout << "your height is " << height_inches / 12 << " foot and " << height_inches % 12 << " inches" << endl;
	system("pause");
	return 0;
}

2.编写一个小程序,要求以几英尺几英寸的方式输入其身高,并以磅为单位输入其体重。(使用3个变量来存储这些信息。)该程序报告其BMI(Body Mass Index,体重指数)。为了计算BMI,该程序以英寸的方式指出用户的身高(1英尺为12英寸),并将以英寸为单位的身高转换为以米为单位的身高(1英寸=0.0254米)。然后,将以磅为单位的体重转换为以千克为单位的体重(1千克=2.2磅)。最后,计算相应的BMI——体重(千克)除以身高(米)的平方。用符号常量表示各种转换因子。

#include <iostream>
using namespace std;


int main(void)
{
	//以几英尺几英寸的方式输入其身高,并以磅为单位输入其体重。
    int  height_foot;
    float height_inches, weight_pounds;
    cout << "Enter your height (in foot):";
    cin >> height_foot;
    cout << "And enter your height (in inches):";
    cin >> height_inches;
    cout << "Enter your weight(in pound):";
    cin >> weight_pounds;
    cout << "So you are " << height_foot << " foot and " << height_inches
        << " inches height and " << weight_pounds << " pounds weight." << endl;

    //以英寸的方式指出用户的身高(1英尺为12英寸)
    const int foot_inches = 12;
    float convert_to_inches;
    convert_to_inches = 12 * height_foot + height_inches;
    cout << "Your height is " << convert_to_inches << " inches" << endl;

    //以英寸为单位的身高转换为以米为单位的身高(1英寸 = 0.0254米)
    const float inches_to_meters = 0.0254;
    float height_meters = convert_to_inches * inches_to_meters;
    cout << "Your height is " << height_meters << " meters" << endl;

    //将以磅为单位的体重转换为以千克为单位的体重(1千克 = 2.2磅)
    const float kg_to_pounds = 2.2;
    float weight_kg = weight_pounds / kg_to_pounds;
    cout << "Your weight is " << weight_kg << " kg." << endl;

    //计算相应的BMI——体重(千克)除以身高(米)的平方。
    float BMI = weight_kg / pow(height_meters, 2);
    cout << "Your BMI is " << BMI << "!" << endl;

	system("pause");
	return 0;
}

3.编写一个程序,要求用户以度、分、秒的方式输入一个纬度;然后以度为单位显示该纬度。1度为60分,1分等于60秒,请以符号常量的方式表示这些值。对于每个输入值,应使用一个独立的变量存储它。下面是该程序运行时的情况:
Enter a latitude in degrees,minutes, and seconds:

First, enter the degrees: 37
Next, enter the minutes of arc:51

Finally, enter the seconds of arc: 19
37 degrees,51 minutes, 19 seconds = 37.8553 degrees


//1度为60分,1分等于60秒,请以符号常量的方式表示这些值。
//对于每个输入值, 应使用一个独立的变量存储它。下面是该程序运行时的情况:
//
//
//	First, enter the degrees : 37
//	Next, enter the minutes of arc : 51
//
//	Finally, enter the seconds of arc : 19
//	37 degrees, 51 minutes, 19 seconds = 37.8553 degrees
#include <iostream>
using namespace std;

int main(void)
{
	//要求用户以度、分、秒的方式输入一个纬度
	int degrees, minutes, seconds;
	float convert_to_degrees;
	cout << "Enter a latitude in degrees, minutes, and seconds :" << endl;
	cout << "First, enter the degrees :";
	cin >> degrees;
	cout << "Next, enter the minutes of arc :";
	cin >> minutes;
	cout << "Finally, enter the seconds of arc :";
	cin >> seconds;

	//以度为单位显示该纬度。
	const int degrees_minutes = 60;
	const int degrees_seconds = 360;
	convert_to_degrees = degrees + (minutes / degrees_minutes) + (seconds / degrees_seconds);
	cout << degrees << " degrees, " << minutes << " minutes, " << seconds << " seconds = " <<
		convert_to_degrees << " degrees" << endl;

	system("pause");
	return 0;
}

4.编写一个程序,要求用户以整数方式输入秒数(使用long或long long变量存储),然后以天、小时、分钟和秒的方式显示这段时间。使用符号常量来表示每天有多少小时、每小时有多少分钟以及每分钟有多少秒。该程序的输出应与下面类似:
Enter the number of seconds: 31600000
31600000 seconds = 365 days,17 hours,46 minutes,40 seconds.

#include <iostream>
using namespace std;

int main(void)
{
	//要求用户以整数方式输入秒数
	long long before_seconds = 0;
	cout << "Enter the number of seconds :";
	cin >> before_seconds;

	//使用符号常量来表示每天有多少小时、每小时有多少分钟以及每分钟有多少秒
	const int day_hour = 24;
	const int hour_minute = 60;
	const int minute_second = 60;

	//以天、小时、分钟和秒的方式显示这段时间
	int days,hours,minutes,seconds;
	days = before_seconds / (day_hour * hour_minute * minute_second);
	hours = (before_seconds % (day_hour * hour_minute * minute_second)) / (hour_minute * minute_second);
	minutes = (before_seconds - days * day_hour * hour_minute * minute_second - hours * hour_minute * minute_second) / minute_second;
	seconds = (before_seconds - days * day_hour * hour_minute * minute_second - hours * hour_minute * minute_second) % minute_second;
	cout << before_seconds << " seconds " << "= " << days << " days,"<<
		hours << " hours, " << minutes << " minutes," << seconds << " seconds" << endl;
	
	system("pause");
	return 0;
}


5.编写一个程序,要求用户输入全球当前的人口和美国当前的人口(或其他国家的人口)。将这些信息存储在 long long变量中,并让程序显示美国(或其他国家)的人口占全球人口的百分比。该程序的输出应与下面类似:
Enter the world's population: 6898758899

Enter the population of  the US : 310783781
The population of the US is 4.50492% of the world population.

#include <iostream>
using namespace std;

int main(void)
{
	//要求用户输入全球当前的人口和美国当前的人口
	long long population_world,population_US;
	cout << "Enter the world's population:";
	cin >> population_world;
	cout << "Enter the population of  the US :";
	cin >> population_US;

	//显示美国的人口占全球人口的百分比
	double percent = 100*((double)population_US / (double)population_world);
	cout << "The population of the US is " << percent<< "% of the world population." << endl;

	system("pause");
	return 0;
}

总结:刚开始没有对population_US 和population_world进行类型转换,导致结果不正确,应该注意先进行类型转换。100*((double)population_US / (double)population_world);
6.编写一个程序,要求用户输入驱车里程(英里)和使用汽油量(加仑),然后指出汽车耗油量为一加仑的里程。如果愿意,也可以让程序要求用户以公里为单位输入距离,并以升为单位输入汽油量,然后指出欧洲风格的结果—-—即每100公里的耗油量(升)。

#include <iostream>
using namespace std;
int main(void)
{
	double miles, gal;
	cout << "Please enter the mileage(miles):";
	cin >> miles;
	cout << "Please enter the amount of gasoline used(Gal):";
	cin >> gal;
	cout<<"The fuel consumption of the car is "<<miles/gal<<" miles/gallon"<<endl;
	system("pause");
	return 0;
}

7.编写一个程序,要求用户按欧洲风格输入汽车的耗油量(每100公里消耗的汽油量(升)),然后将其转换为美国风格的耗油量―—每加仑多少英里。注意,除了使用不同的单位计量外,美国方法(距离/燃料)与欧洲方法(燃料/距离)相反。100公里等于62.14英里,1加仑等于3.875升。因此,19mpg大约合12.41/100km,127mpg大约合8.71/100km。(此处有误,应该是27而不是127)

#include <iostream>
using namespace std;

int main(void)
{
	//用户按欧洲风格输入汽车的耗油量(每100公里消耗的汽油量(升))
	double consumption_Eur;
	int mpg;
	cout << "Enter the fuel consumption of the vehicle (per 100 km):";
	cin >> consumption_Eur;
	//将其转换为美国风格的耗油量―每加仑多少英里
	const double _100km_mile = 62.14;
	const double gai_L = 3.875;
	mpg = _100km_mile/(consumption_Eur / gai_L) ;
	cout << "So your fuel consumption of the vehicle is " << mpg << "mpg" << endl;

	system("pause");
	return 0;
}

第4章 复合类型

1.编写一个C++程序,如下述输出示例所示的那样请求并显示信息:

what is your first name? Betty sue

what is your last name? Yewe
what letter grade do you deserve? B

what is your age? 22
Name: Yewe,Betty sue

Grade : c
Age: 22
注意,该程序应该接受的名字包含多个单词。另外,程序将向下调整成绩,即向上调一个字母。假设用户请求A、B或C,所以不必担心D和F之间的空档。

解答:该程序应该接受的名字包含多个单词。所以应该使用cin.getline()而非cin();

#include <iostream>
using namespace std;
#define MaxSize 80
int main(void)
{
	char firstName[MaxSize];
	char lastName[MaxSize];
	char Grade;
	int Age;

	cout << "What is your first name?";
	cin.getline(firstName, MaxSize);
	cout << "What is your last name?";
	cin.getline(lastName, MaxSize);
	cout << "what letter grade do you deserve?";
	cin >> Grade;
	cout << "what is your age?";
	cin >> Age;

	Grade = Grade + 1;

	cout << "Name: " << lastName << ", " << firstName << endl;
	cout << "Grade: " << Grade << endl;
	cout << "Age: " << Age << endl;

	system("pause");
	return 0;
}

2.修改程序清单4.4,使用C++ string类而不是char数组。

解答:将一行输入读到string对象中的代码:getline(cin,str);(书p87)

#include <iostream>
#include <string>
using namespace std;

int main(void)
{
	string  name;
	string desert;

	cout << "Enter your name:" << endl;
	getline(cin, name);
	cout << "Enter your favorite desert:" << endl;
	getline(cin, desert);
	cout << "I have some delicious " << desert << " for you, " << name << endl;

	system("pause");
	return 0;
}

3.编写一个程序,它要求用户首先输入其名,然后输入其姓;然后程序使用一个逗号和空格将姓和名组合起来,并在储和显示组合结果。请使用char数组和头文件cstring中的函数。下面是该程序运行时的情形:
Enter your first name: Flip
Enter your last name: Fleming
Here's the information in a single string:Fleming,Flip

解答:strcat()函数可以用来将两个char类型变量连接起来形成新的char类型变量的函数,该函数在头文件cstring中被定义,比如

char a[20] = "abcd";

char b[20] = "cba";

strcat(a, b);

cout << a;

以上代码输出“abcdcba”,中间不会有间隔,将b连接到a的后面,形成新的char数组赋给a。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
using namespace std;
int main(void)
{
	const int ArSize = 80;
	char firstname[ArSize];  
	char lastname[ArSize];

	cout << "Enter your first name:" << endl;
	cin.getline(firstname, ArSize);
	cout << "Enter your last name:" << endl;
	cin.getline(lastname, ArSize);
	strcat(lastname, ", ");     //把一个逗号和空格与lastname组合起来并赋给数组lastname
	strcat(lastname, firstname);//将firstname与lastname数组结合起来赋给lastname数组
	cout << "Here's the information in a single string:" << lastname << endl;

	system("pause");
	return 0;
}

4.编写一个程序,它要求用户首先输入其名,再输入其姓;然后程序使用一个逗号和空格将姓和名组合起来,并存储和显示组合结果。请使用string对象和头文件 string 中的函数。下面是该程序运行时的情形:
Enter your first name: Flip

Enter your last name:  Fleming
Here's the information in a single string: Fleming,Flip.

解答:与上题不同,string对象的字符串拼接使用运算符即可完成。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
using namespace std;
int main(void)
{
	string firstname;
	string lastname;

	cout << "Enter your first name:" << endl;
	getline(cin, firstname);
	cout << "Enter your last name:" << endl;
	getline(cin, lastname);
	string str = lastname + ", " + firstname;
	cout << "Here's the information in a single string:" << str << endl;

	system("pause");
	return 0;
}

5.结构CandyBar包含3个成员。第一个成员存储了糖块的品牌;第二个成员存储糖块的重量(可以有小数)、第三个成员存储了糖块的卡路里含量(整数)。请编写一个程序,声明这个结构创建一个名为snack 的 CandyBar变量,并将其成员分别初始化为“Mocha Munch”、2.3和350。初始化应在声明snack时进行。最后,程序显示 snack变量的内容。

#include <iostream>
using namespace std;
//定义结构
struct CandyBar
{
	string brand;
	float weight;
	int   calorie;
};
int main(void)
{
	CandyBar snack =
	{
		"Mocha Munch",
		2.3,
		350
	};

	cout << "Brand: " << snack.brand << "\tweight: " << snack.weight << "\tcalorie: " << snack.calorie << endl;

	system("pause");
	return 0;
}

6.结构 CandyBar包含3个成员。如编程练习5所示。请编写一个程序,创建一个包含3个元素的CandyBar数维,并将它们初始化为所选择的值,然后显示每个结构的内容。.

#include <iostream>
using namespace std;
//定义结构
struct CandyBar
{
	string brand;
	float weight;
	int   calorie;
};
int main(void)
{
	CandyBar snack[3] =
	{
		{"Mocha Munch",2.3,350},
		{"Fruit Salad",5.2,200},
		{"hamburger",2.6,1000}
	};

	cout << "Brand: " << snack[0].brand << "\tweight: " << snack[0].weight 
		<< "\tcalorie: " << snack[0].calorie << endl;
	cout << "Brand: " << snack[1].brand << "\tweight: " << snack[1].weight
		<< "\tcalorie: " << snack[1].calorie << endl;
	cout << "Brand: " << snack[2].brand << "\tweight: " << snack[2].weight
		<< "\tcalorie: " << snack[2].calorie << endl;

	system("pause");
	return 0;
}

7.William Wingate从事披萨饼分析服务。对于每个披萨饼,他都需要记录下列信息:

1.披萨饼公司的名称,可以有多个单词组成。
2.披萨饼的直径。
3.披萨饼的重量。
请设计一个能够存储这些信息的结构,并编写一个使用这种结构变量的程序。程序将请求用户输入上述信息;然后显示这些信息。请使用_cin(或其它的方法)和 cout。

#include <iostream>
#include <string>
using namespace std;
//定义结构
struct Pizza
{
	string Name;
    float diameter;
	float weight;
};
int main(void)
{
	Pizza a;
	cout << "Enter the name of commpany:";
	getline(cin, a.Name);
	cout << "Enter the diameter of Pizza:";
	cin >> a.diameter;
	cout << "Enter the weight of Pizza:";
	cin>>a.weight;
	cout << "Name: " << a.Name<< "\tweight: " << a.weight
		<< "\tdiameter: " << a.diameter << endl;
	
	system("pause");
	return 0;
}


8.完成编程练习7,但使用new来为结构分配内存,而不是声明一个结构变量。另外,让程序在请求输入比萨饼公司名称之前输入比萨饼的直径。

解答:

  1. 使用new为结构分配内存;注意:用指针去接,以及访问结构成员的时候用箭头访问。
  2. (书p81)先输直径后输入文字,考察怎么处理遗留在输入序列中的换行符问题。如果直接cin读取直径,将会把回车键生成的换行符留在输入队列中,后面的cin.getline()看到换行符后,将会认为是一个空行,并把空行赋给Name字符串。随意需要在读入公司名称前丢弃换行符。解决方式如下:
#include <iostream>
#include <string>
using namespace std;
//定义结构
struct Pizza
{
	string Name;
	float diameter;
	float weight;
};
int main(void)
{
	Pizza* a = new Pizza;
	cout << "Enter the diameter of Pizza:";
	(cin >> a->diameter).get();   //or cin>>a->diameter; cin.get();
	cout << "Enter the name of commpany:";
	getline(cin, a->Name);
	cout << "Enter the weight of Pizza:";
	cin >> a->weight;
	cout << "Name: " << a->Name << "\tweight: " << a->weight
		<< "\tdiameter: " << a->diameter << endl;
	delete a;
	system("pause");
	return 0;
}


9.完成编程练习6,但使用new来动态分配数组,而不是声明一个包含3个元素的CandyBar 数组。

#include <iostream>
using namespace std;
//定义结构
struct CandyBar
{
	string brand;
	float weight;
	int   calorie;
};


int main(void)
{
	const int Size = 3;
	CandyBar* snack = new CandyBar[Size];

	snack[0] = { "Mocha Munch",2.3,350 };
	snack[1] = { "Fruit Salad",5.2,200 };
	snack[2] = { "hamburger",2.6,1000 };

	for (int i = 0; i < Size; i++)
	{
		cout << "Brand:" << snack[i].brand << "      weight:" << snack[i].weight
			<< "      calorie:" << snack[i].calorie << endl;
	}
	delete[] snack;

	system("pause");
	return 0;
}

10:编写一个程序,让用户输入三次40码跑的成绩(如果您愿意,也可让用户输入40米跑的成绩),并显示次数和平均成绩。请使用一个array对象来存储数据(如果编译器不支持array 类,请使用数组)。

解答:array<typeName,n_elem> arr;

代码写的不好,写成函数应该更好。不懂模板类数组的调用,后续有时间再改;

#include <iostream>
#include <array>
using namespace std;

int main(void)
{
	const int num = 3;
	array<double, num> score;
	
	//输入成绩
	cout << "Please enter the result of your first 40 yard run:";
	cin >> score[0];
	cout << "Please enter the result of your second 40 yard run:";
	cin >> score[1];
	cout << "Please enter the result of your third 40 yard run:";
	cin >> score[2];

	//输出成绩
	for (int i = 0; i < num; i++)
	{
		cout << "第" << i+1 << "次成绩:" << score[i] << endl;
	}

	//平均成绩
	double sum = 0;
	for (int i = 0; i < num; i++)
	{
		sum += score[i];
	}
	cout << "your average score is:" << sum / num << endl;

	system("pause");
	return 0;
}

第5章 循环和关系表达式

1.编写一个要求用户输入两个整数的程序。该程序将计算并输出这两个整数之间(包括这两个整数)所有整数的和。这里假设先输入较小的整数。例如,如果用户输入的是2和9,则程序将指出2~9之间所有整数的和为44。

//编写一个要求用户输入两个整数的程序。
//该程序将计算并输出这两个整数之间(包括这两个整数)所有整数的和。
//这里假设先输入较小的整数。
//例如,如果用户输入的是2和9,则程序将指出2~9之间所有整数的和为44。
#include <iostream>
using namespace std;
int main(void)
{
	int a;
	int b;
	int sum1 = 0;
	int sum2 = 0;
	int sum3 = 0;
	cout << "请输入第一个整数:";
	cin >> a;
	cout << "请输入第二个整数:";
	cin >> b;
	法一:for循环
	//for (; a <= b; a++) 
	//	sum1 += a;
	//cout << "您输入的两个整数之间所有整数的和为:" << sum1 << endl;
	//法二:while循环
	while (a <= b)
	{
		sum2 += a;
		a++;
	}
	cout << "您输入的两个整数之间所有整数的和为:"<< sum2 << endl;
	法三:do while循环
	//do
	//{
	//	sum3 += a;
	//	a++;
	//} while (a <= b);
	//cout << "您输入的两个整数之间所有整数的和为:" << sum3 << endl;

	system("pause");
	return 0;
}

2.使用 array对象(而不是数组)和 long double(而不是long long)重新编写程序清单5.4,并计算100!的值。

//使用 array对象(而不是数组)和 long double(而不是long long)重新编写程序清单5.4,
//并计算100!的值。
//array在书p120  array<typeName,n_elm>arr;
#include <iostream>
#include <array>
using namespace std;
int main(void)
{
	const int arrSize = 101;
	array<long double, arrSize> arr;
	arr[0] = arr[1] = 1;
	for (int i = 2; i < arrSize; i++)
	{
		arr[i] = i * arr[i - 1];
	}
	cout << "100! = " << arr[100] << endl;

	system("pause");
	return 0;
}

3.编写一个要求用户输入数字的程序。每次输入后,程序都将报告到目前为止,所有输入的累计和。当用户输入0时,程序结束。

//编写一个要求用户输入数字的程序。每次输入后,
//程序都将报告到目前为止,所有输入的累计和。
//当用户输入0时, 程序结束。
#include <iostream>
using namespace std;
int main(void)
{
	double a;
	double sum = 0;
	cout << "请输入一个数字(输入0程序结束):" ;
	while (cin >> a && a)
	{
		sum += a;
		cout << "目前为止,所有输入的和为:" << sum << endl;
		cout << "请输入一个数字(输入0程序结束):" ;
	}
	system("pause");
	return 0;
}

4.Daphne 以10%的单利投资了100美元。也就是说,每一年的利润都是投资额的10%,即每年10美元:利息=0.10×原始存款
而Cleo以5%的复利投资了100美元。也就是说,利息是当前存款(包括获得的利息的5%,:
利息=0.05×当前存款
Cleo在第一年投资100美元的盈利是5%——得到了105美元。下一年的盈利是105美元的5%—--即5.25美元,依此类推。请编写一个程序,计算多少年后,Cleo 的投资价值才能超过Daphne的投资价值,并显示此时两个人的投资价值。

//4.Daphne 以10 % 的单利投资了100美元。
//也就是说,每一年的利润都是投资额的10 % ,即每年10美元:利息 = 0.10×原始存款
//而Cleo以5 % 的复利投资了100美元。也就是说,利息是当前存款(包括获得的利息的5%, :
//	利息 = 0.05×当前
//Cleo在第一年投资100美元的盈利是5 % ——得到了105美元。
//下一年的盈利是105美元的5 % —即5.25美元,依此类推。
//请编写一个程序,计算多少年后,Cleo 的投资价值才能超过Daphne的投资价值,
//并显示此时两个人的投资价值。
#include <iostream>
using namespace std;
int main(void)
{
	double Cleo = 100;
	double Daph = 100;
	int year_count = 0;
	do
	{
		Daph += 100 * 0.1;
		Cleo += Cleo * 0.05;
		year_count++;

	} while (Cleo < Daph);
	cout <<  year_count << "年后, Cleo投资价值超过Daph."<<endl;
	cout<<"Daphene:" << Daph << "\tCleo:" << Cleo << endl;
	
	system("pause");
	return 0;
}


5.假设要销售《C++ For Fools》一书。请编写一个程序,输入全年中每个月的销售量(图书数量,而不是销售额)。程序通过循环,使用初始化为月份字符串的char*数组(或string对象数组逐月进行提示,并将输入的数据储存在一个int数组中。然后,程序计算数组中各元素的总数,并报告这一年的销售情况。

//假设要销售《C++ For Fools》一书。
//请编写一个程序,输入全年中每个月的销售量(图书数量,而不是销售额)。
//程序通过循环,使用初始化为月份字符串的char* 数组
//(或string对象数组逐月进行提示, 并将输入的数据储存在一个int数组中。
//然后,程序计算数组中各元素的总数,并报告这一年的销售情况。
#include <iostream>
using namespace std;
int main(void)
{
	//初始化为月份字符串的string对象数组
	string months[12] = {
	"January", "February", "March",
	"April", "May", "June","July",
	"August", "September", "October",
	"November","December"
	};
	int sales[12];

	int sum = 0;
	for (int i = 0; i < 12; i++)
	{
		cout << "Please enter the sales volume for " << months[i] << " :";
		cin >> sales[i];
	}

	for (int i = 0; i < 12; i++)
	{
		cout << months[i] << " sales : " << sales[i] << endl;
     	sum += sales[i];
	}
	cout << "Annual sales :" << sum << endl;

	system("pause");
	return 0;
}

6.完成编程练习5,但这一次使用一个二维数组来存储输入——3年中每个月的销售量。程序将报告每年销售量以及三年的总销售量。

#include <iostream>
using namespace std;
int main(void)
{
	//初始化为月份字符串的string对象数组
	string months[12] = {
	"January", "February", "March",
	"April", "May", "June","July",
	"August", "September", "October",
	"November","December"
	};
	int sales[3][12];   //二维数组存储三年每个月的销量
	int sum[3] = {0};

	for (int i = 0; i < 3; i++)
	{
		cout << "Year" << i + 1 << ":" << endl;
		for (int j = 0; j < 12; j++)
		{
			cout << "Please enter the sales volume for " << months[j] << " :";
			cin >> sales[i][j];
			sum[i] += sales[i][j];
		}
		cout << (i + 1) << " year sales:" << sum[i] <<  endl;
	}
	cout << "The saLes of three year is " << sum[0] + sum[1] + sum[2] << endl;

	system("pause");
	return 0;
}

7.设计一个名为car的结构,用它存储下述有关汽车的信息:生产商(存储在字符数组或string对象中的字符串)、生产年份(整数) 编写一个程序,向用户询问有多少辆汽车。随后,程序使用new来创建一个由相应数量的car结构组成的动态数组。接下来,程序提示用户输入每辆车的生产商(可能由多个单词组成)和年份信息。请注意,这需要特别小心,因为它将交替读取数值和字符串(参见第4章)。最后,程序将显示每个结构的内容。该程序的运行情况如下:

How many cars do you wish to catalog? 2

car #1:
Please enter the make: Hudson  Hornet

Please enter the year made: 1952
car #2:
please  efter themake: Kaiser

please enter  the year made:1951

Here is your colrection :
1952 Hudson Hornet
1951 Kaiser

//设计一个名为car的结构,用它存储下述有关汽车的信息:
//生产商(存储在字符数组或string对象中的字符串)、
//生产年份(整数) 
//编写一个程序,向用户询问有多少辆汽车。
//随后,程序使用new来创建一个由相应数量的car结构组成的动态数组。
//接下来,程序提示用户输入每辆车的生产商(可能由多个单词组成)和年份信息。
//请注意,这需要特别小心,因为它将交替读取数值和字符串(参见第4章)。
//最后,程序将显示每个结构的内容。
#include <iostream>
#include <string>
using namespace std;
//设计一个名为car的结构
struct Car
{ 
	string producer;        //生产商
	int MadeYear;              //生产年份

};

int main(void)
{
	int Num; //汽车数量
	//向用户询问有多少辆汽车。
	cout << "How many cars do you wish to catalog?" ;
	cin >> Num;
	cin.get();
	Car* pt = new Car[Num];
	for (int i = 0; i < Num; i++)
	{
		cout << "car #" << i+1 << ":" << endl;
		cout << "Please enter the make:";
		getline(cin, pt[i].producer);
		cout << "please enter the year made:";
		cin >> pt[i].MadeYear;
		cin.get();
	}
	cout << "Here is your colrection :" << endl;
		for (int i = 0; i < Num; i++)
		{
			cout << pt[i].MadeYear << "   " << pt[i].producer << endl;
		}

	system("pause");
	return 0;
}

8.编写个程序,它使用一个char数组和循环来每次读取一个单词,直到用户输入done为止。随后,该程序指出用户输入了多少个单词(不包括done在内)。下面是该程序的运行情况:
Enter words (to stop, type the word done):
anteater birthday category  dumpster
envy finagle geometry done for sure

You  entered a total of 7 words.
您应在程序中包含头文件cstring,并使用函数strcmp()来进行比较测试。

解:书p143

#include <iostream>
#include <cstring>
using namespace std;
#define MaxSize 30
int main(void)
{
	char word[MaxSize];
	int count = 0;
	cout << "Enter words (to stop, type the word done):" << endl;
	cin >> word;

	while (strcmp(word, "done"))
	{
		count++;
		cin >> word;
	}

	cout<<"You  entered a total of "<<count<<" words."<<endl;
	system("pause");
	return 0;
}

9.编写一个满足前一个练习中描述的程序,但使用string对象而不是字符数组。请在程序中包含头文件string并使用关系运算符来进行比较测试。

#include <iostream>
#include <cstring>
using namespace std;

int main(void)
{
	string word;
	int count = 0;
	cout << "Enter words (to stop, type the word done):" << endl;
	cin >> word;

	while (word != "done")
	{
		count++;
		cin >> word;
	}

	cout << "You  entered a total of " << count << " words." << endl;
	system("pause");
	return 0;
}

10.编写一个使用嵌套循环的程序,要求用户输入一个值,指出要显示多少行。然后,程序将显示相应行数的星号,其中第一行包括一个星号,第二行包括两个星号,依此类推。每一行包含的字符数等于用户指定的行数,在星号不够的情况下,在星号前面加上句点。该程序的运行情况如下:
Enter number of rows :5
....*

...**

..***

.****

*****
 

#include <iostream>
using namespace std;

int main(void)
{
	int Num = 0;
	cout << "Enter number of rows :";
	cin >> Num;
	for (int i = 1; i <= Num; i++)
	{
		for (int j = i; j < Num; j++)
		{
			cout << ".";
		}
		for (int j = 0; j < i; j++)
		{
			cout << "*";
		}
		cout << endl;
	}

	system("pause");
	return 0;
}

第6章 分支语句和逻辑运算符

1.编写一个程序,读取键盘输入,直到遇到@符号为止,并回显输入(数字除外),同时将大写字符转换为小写,将小写字符转换为大写(别忘了cctype函数系列)。

//1.读取键盘输入,直到遇到@
//2.回显除了数字以外的输入 isdigit
//3.大写转小写 tolower()   小写转大写toupper()
#include <iostream>
#include <cctype>
using namespace std;
int main(void)
{
	char ch;
	cout << "Enter text for analysis, and type @ to terminate input:"<<endl;
	cin.get(ch);
	while ((ch != '@'))
	{
		
		if (islower(ch))
		{
			ch = toupper(ch);
		}
		else if (isupper(ch))
		{
			ch = tolower(ch);
		}
		if (isdigit(ch) == false)
		{
			cout << ch;
		}
		cin.get(ch);
	}


	system("pause");
	return 0;
}

2.编写一个程序,最多将10个donation值读入到一个double数组中(如果您愿意,也可使用模板类array)。程序遇到非数字输入时将结束输入,并报告这些数字的平均值以及数组中有多少个数字大于平均值。

//编写一个程序,最多将10个donation值读入到一个double数组中
//(如果您愿意,也可使用模板类array)。
//程序遇到非数字输入时将结束输入,
//并报告这些数字的平均值以及数组中有多少个数字大于平均值
//6.7读取数字的循环 p187 程序清单6.13
#include <iostream>
#include <array>
using namespace std;
#define max  10

int main(void)
{
	array<double, max> donation;
	cout << "Enter the elements you want to exist in the array "
		<<"( a non number input to terminate):"<<endl;
	int i = 0;
	double sum = 0;
	int n_elem = 0;
	int n_above = 0;
	while (i < max && cin >> donation[i])
	{
		n_elem++;
		sum += donation[i];
	}
	double average = sum / n_elem;
	for (i = 0; i < max; i++)
	{
		if (donation[i] > average)
			n_above++;
	}
	cout << "average = " << average << endl;
	cout << n_above << " numbers greater than average" << endl;
	

	system("pause");
	return 0;
}

3.编写一个菜单驱动程序的雏形。该程序显示一个提供4个选项的菜单——每个选项用一个字母标记。如果用户使用有效选项之外的字母进行响应,程序将提示用户输入一个有效的字母,直到用户这样做为止。然后,该程序使用一条switch语句,根据用户的选择执行一个简单操作。该程序的运行情况如下:
Please enter one of the following choices :
c) carnivore       p) pianist
t) tree                 g) game
f
Please enter a c, p, t, or g: q

Please enter a c, p,t, or g: t

A maple is a tree.

#include <iostream>
using namespace std;
int main(void)
{
	char ch;
	cout << "Please enter one of the following choices :" << endl;
	cout << "c) carnivore " << "\t p) pianist" << endl;
	cout<<  " t) tree" << "     \tg) game" << endl;
	
	while (cin >> ch)
	{
		switch (ch)
		{
		case 'c':
			cout << "tiger is a carnivore." << endl;
			break;
		case 'p':
			cout << "Xiaoming is a pianist." << endl;
			break;
		case 't':
			cout << "A maple is a tree." << endl;
			break;
		case 'g':
			cout << "Golf is a game." << endl;
			break;
		default:
			cout << "Please enter a c, p, t, or g: ";

		}
	}

	system("pause");
	return 0;
}

4.加入 Benevolent Order of Programmer后,在 BOP大会上,人们便可以通过加入者的真实姓名、头衔或秘密BOP姓名来了解他(她)。请编写一个程序,可以使用真实姓名、头衔、秘密姓名或成员偏好来列出成员。编写该程序时,请使用下面的结构:
// Benevolent Order of Programmers name structure

struct bop {
char fullname [strsize] ;// real name

char title[strsize] ;         // job title
char bopname [strsize] ;  //secret BOP name
int preference;                //0 = fullname,1 = title, 2 = bopname);
该程序创建一个由上述结构组成的小型数组,并将其初始化为适当的值。另外,该程序使用一个循环,让用户在下面的选项中进行选择:
a. display by name            b. display by title
c. display by bopname      d. display by preference
q. quit
注意,“display by preference”并不意味着显示成员的偏好,而是意味着根据成员的偏好来列出成员。例如,如果偏好号为1,则选择d将显示程序员的头衔。该程序的运行情况如下:

Benevolent order of Programmers Report
a. display by name         b. display by title
c. display by bop

name   d. display by preference

q. quit
Enter your choice: a

wimp Macho
Raki Rhodes

Celia Laiter

Hoppy Hipman

Pat Hand
Next choice: d

wimp Macho
Junior Programmer

MIPS
Analyst Trainee

LOOFY
Next choice: q

Bye!

#include <iostream>
using namespace std;
const int strsize = 20;
const int n_elm = 5;
// Benevolent Order of Programmers name structure
struct bop
{
	char fullname[strsize];// real name
	char title[strsize];         // job title
	char bopname[strsize];  //secret BOP name
	int preference;         //0 = fullname,1 = title, 2 = bopname);
};
bop exampel[n_elm] =
{
	{ "Wimp Mache", "BOSS", "AS", 0 },
	{ "Raki Rhodes", "Junior Programmer", "MA", 1 },
	{ "Celia Laiter", "Manager", "MIPS", 2 },
	{ "Hoppy Hipman", "Analyst Trainee", "CL", 1 },
	{ "Pat Hand", "Student", "LOOPY", 2 }
};
void display_name(void)
{
	for (int j = 0; j < n_elm; j++)
		cout << exampel[j].fullname<< endl;
}
void display_title(void)
{
	for (int j = 0; j < n_elm; j++)
		cout << exampel[j].title << endl;
}
void display_bopname(void)
{
	for (int j = 0; j < n_elm; j++)
		cout << exampel[j].bopname<< endl;
}
void display_perference(void)
{
	for (int j = 0; j < n_elm; j++)
	{
		if (exampel[j].preference == 0)
			cout << exampel[j].fullname << endl;
		else if (exampel[j].preference == 1)
			cout << exampel[j].title << endl;
		else
			cout << exampel[j].bopname << endl;
	}
}
int main(void)
{
	char ch;
	cout << "Benevolent Order of Programmers Report" << endl;
	cout<< "a.display by name          b.display by title" << endl;
	cout<< "c.display by bopname       d.display by preference" << endl;
	cout<< "q.quit"<<endl;
	cout << "Enter your chlice:";
	while (cin >> ch && ch !='q')
	{
		switch (ch)
		{
		case 'a':
			display_name();
			break;
		case 'b':
			display_title();
			break; 
		case 'c':
			display_bopname();
			break;
		case 'd':
			display_perference();
			break;
		}
		cout << "Next choice:";
	}
	cout << "Bye!" << endl;
	system("pause");
	return 0;
}

5.在 Ncutronia王国,货币单位是tvarp,收入所得税的计算方式如下:

5000 tvarps:不收税
5001~15000 tvarps:10%

15001~35000 tvarps:15%

35000 tvarps 以上:20%
例如,收入为38000 tvarps 时,所得税为5000 × 0.00 + 10000 × 0.10 +20000 × 0.15 + 3000 × 0.20,即4600 tvarps。请编写一个程序,使用循环来要求用户输入收入,并报告所得税。当用户输入负数或非数字时,循环将结束。

#include <iostream>
using namespace std;

int main(void)
{
	int  income;
	cout << "Enter your income:";
	while (cin >> income && income >= 0)
	{
		if (income <= 5000)
		{
			cout << "tax = 0" << endl;
		}
		else if (income > 5000 && income <= 15000)
		{
			cout << "tax = " << (double)(income - 5000) * 0.1<<"tvarps"<< endl;
		}
		else if (income > 15000 && income < 35000)
		{
			cout << "tax = " << 0 + (15000 - 5000) * 0.1 + (double)(income - 15000) * 0.15 << "tvarps" << endl;
		}
		else
		{
			cout << "tax = " << 0 + (15000 - 5000) * 0.1 + (35000 - 15000) * 0.15+(double)(income - 35000)*0.2 << "tvarps" << endl;
		}
		cout << "Enter your income:";

	}
	system("pause");
	return 0;

}

6.编写一个程序,记录捐助给“维护合法权利团体”的资金。该程序要求用户输入捐献者数目,然后要求用户输入每一个捐献者的姓名和款项。这些信息被储存在一个动态分配的结构数组中。每个结构有两个成员:用来储存姓名的字符数组(或string对象)和用来存储款项的double成员。读取所有的数据后,程序将显示所有捐款超过10000的捐款者的姓名及其捐款数额。该列表前应包含一个标题,指出下面的捐款者是重要捐款人(Grand Patrons)。然后,程序将列出其他的捐款者,该列表要以Patrons开头。如果某种类别没有捐款者,则程序将打印单词“none”。该程序只显示这两种类别,而不进行排序。

#include <iostream>
#include <string>
using namespace std;
//用来储存姓名的字符数组(或string对象)和用来存储款项的double成员
struct information
{
	string name;
	double money;
};

//显示所有捐款超过10000的捐款者的姓名及其捐款数额。
void show_Grand(information* info, int num)
{
	cout << "Grand Patrons:" << endl;
	int n_Grand = 0;
	for (int j = 0; j < num; j++)
	{
		if (info[j].money> 10000)
		{
			cout << info[j].name << "\t" << info[j].money << endl;
			n_Grand++;
		}
	}
	if (n_Grand == 0)
	{
		cout << "none" << endl;
	}
}

//程序将列出其他的捐款者,该列表要以Patrons开头。
void show_other(information* info, int num)
{
	cout << "Patrons:" << endl;
	int n_other = 0;
	for (int j = 0; j < num; j++)
	{
		if (info[j].money <= 10000)
		{
			cout << info[j].name << "\t" << info[j].money << endl;
			n_other++;
		}
	}
	if (n_other == 0)
	{
		cout << "none" << endl;
	}

}
int main(void)
{
	int num;       //捐献者数目
	cout << "Pleser enter the number of donors: ";
	cin >> num;
	cin.get();    //清除缓存 后面还要输入字母
	information* info = new information[num]; //这些信息被储存在一个动态分配的结构数组中。
	
											  //要求用户输入每一个捐献者的姓名和款项。
	for (int i = 0; i < num; i++)
	{
		cout << "Please enter the " << i + 1 << "-th name: ";
		getline(cin, info[i].name);
		cout << "Please enter the " << i + 1 << "-th money:";
		cin >> info[i].money;
		cin.get();
	}
	show_Grand(info, num);
	show_other(info, num);

	system("pause");
	return 0;
}

7.编写一个程序,它每次读取一个单词,直到用户只输入q。然后,该程序指出有多少个单词以元音打头,有多少个单词以辅音打头,还有多少个单词不属于这两类。为此,方法之一是,使用isalpha( )来区分以字母和其他字符打头的单词,然后对于通过了isalpha()测试的单词,使用if或switch语句来确定哪些以元音打头。该程序的运行情况如下:
Enter words (q to quit) :
The 12 awesome oxen ambled
quietly across 15 meters of lawn. q

5 words beginning with vowels
4 words beginning with consonants

2 others

//单词 == 字符数组
#include <iostream>
#include <cctype>
using namespace std;
const int ArrSize = 30;
int main(void)
{
	char ch;
	char str[ArrSize];
	int count_other = 0;
	int count_vowel = 0;
	int count_consonant = 0;
	cout << "Enter words(q to quit) :" << endl;
	while (cin >> str)
	{
		if (strcmp(str, "q") == 0)       //单独一个字母q就退出
			break;
		ch = str[0];
		if (isalpha(ch))
		{

			switch (ch)
			{
			case 'a':
			case 'e':
			case 'i':
			case 'o':
			case 'u':
				count_vowel++;
				break;
			default:
				count_consonant++;
			}
		}
		else
			count_other++;
	}
	cout << count_vowel << " words beginning with vowels\n";
	cout << count_consonant << " words beginning with consonants\n";
	cout << count_other << " others\n";

	system("pause");
	return 0;
}

8.编写一个程序,它打开一个文件文件,逐个字符地读取该文件,直到到达文件末尾,然后指出该文件中包含多少个字符。

解:参考书p195

//8.编写一个程序,它打开一个文件文件,逐个字符地读取该文件,
//直到到达文件末尾,然后指出该文件中包含多少个字符。
#include<iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
const int SIZE = 60;

int main(void)
{
	char filename[SIZE];
	ifstream inFile;
	cout << "Enter name of data file:";
	cin.getline(filename, SIZE);
	inFile.open(filename);

	if (!inFile.is_open())
	{
		cout << "Could not open the file " << filename << endl;
		cout << "Program terminating." << endl;
		exit(EXIT_FAILURE);
	}

	int count = 0;
	char ch;
	inFile >> ch;
	while (inFile.good())
	{
		count++;
		inFile >> ch;
	}
	if (inFile.eof())
		cout << "End of file reached." << endl;
	else if (inFile.fail())
	{
		cout << "Input terminated by data mismatch." << endl;
	}
	else
		cout << "Input terminated for unknown reason." << endl;
	
	cout << "A total of " << count << " characters were read." << endl;
	inFile.close();
	system("pause");
	return 0;
}

9.完成编程练习6,但从文件中读取所需的信息。该文件的第一项应为捐款人数,余下的内容应为成对的行。在每一对中,第一行为捐款人姓名,第二行为捐款数额。即该文件类似于下面;
4
sam stone

2000
Freida Flass

100500
Tammy Tubbs

5000
Rich Raptor

55000

#include <iostream>
#include <string>
#include <fstream>
using namespace std;
const int size = 20;
//用来储存姓名的字符数组(或string对象)和用来存储款项的double成员
struct information
{
	string name;
	double money;
};

//显示所有捐款超过10000的捐款者的姓名及其捐款数额。
void show_grand(information* info, int num)
{
	cout << "grand patrons:" << endl;
	int n_grand = 0;
	for (int j = 0; j < num; j++)
	{
		if (info[j].money> 10000)
		{
			cout << info[j].name << "\t" << info[j].money << endl;
			n_grand++;
		}
	}
	if (n_grand == 0)
	{
		cout << "none" << endl;
	}
}

//程序将列出其他的捐款者,该列表要以patrons开头。
void show_other(information* info, int num)
{
	cout << "patrons:" << endl;
	int n_other = 0;
	for (int j = 0; j < num; j++)
	{
		if (info[j].money <= 10000)
		{
			cout << info[j].name << "\t" << info[j].money << endl;
			n_other++;
		}
	}
	if (n_other == 0)
	{
		cout << "none" << endl;
	}

}
int main(void)
{
	char filename[size];
	ifstream infile;
	cout << "enter name of data file:";
	cin.getline(filename, size);
	infile.open(filename);
	if (!infile.is_open())
	{
		cout << "could not open the file " << filename << endl;
		cout << "program terminating." << endl;
		exit(exit_failure);
	}

	int num;
	int i;
	infile>>num;
	infile.get();    //清除缓存 后面还要输入字母
	information* info = new information[num]; //这些信息被储存在一个动态分配的结构数组中。
	
	for (i = 0; i < num; i++)
	{
		getline(infile, info[i].name);
		infile >> info[i].money;
		infile.get();
	}
	
	show_grand(info, num);
	show_other(info, num);

	system("pause");
	return 0;
}

第7章 函数C++编程模块

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

#include <iostream>
using namespace std;

double Harmonic_mean(double x, double y)
{
	return 2.0 * x * y / (x + y);
}
int main(void)
{
	double x;
	double y;
	cout << "Please input two numbers x and y:(x>0&&y>0):" << endl;
	while (cin >> x >> y && ((x > 0) && (y > 0)))
	{
		double result = Harmonic_mean(x, y);
		cout << x << " and " << y << ":" << result << endl;
		cout << "Input two numbers x and y:(x>0&&y>0):" << endl;
	}
	cout << "Done!" << endl;
	system("pause");
	return 0;
}

2.编写一个程序,要求用户输入最多10个高尔夫成绩,并将其存储在一个数组中。程序允许用户提早结束输入,并在一行上显示所有成绩,然后报告平均成绩。请使用3个数组处理函数来分别进行输入、显示和计算平均成绩。

#include <iostream>
using namespace std;
const int ArrSize = 10;
int True_Size = 0;
//输入
void Input(double *Golf_scores)
{
	cout << "If you want to end the input, press the letter!" << endl;
	for (int i = 0; i < ArrSize; i++)
	{
		cout << "Input the " << i + 1 << "_th Score:" << endl;
		if (cin >> Golf_scores[i])
		{
		}
		else
		{
			True_Size = i;
			break;
		}
		True_Size = i;
	}
	cout << "Enter end!" << endl;
	
}
//显示
void Display(const double* Golf_scores)
{
	cout << "All Scores:";
	for (int i = 0; i < True_Size; i++)
	{
		cout << Golf_scores[i] << "      ";
	}
	cout << endl;
}
//计算平均成绩
void Caculate(double* Golf_scores)
{
	double sum = 0;
	cout << "Average score:";
	for (int i = 0; i < True_Size; i++)
	{
		sum += Golf_scores[i];
	}
	cout << (double)sum/True_Size << endl;
}
int main(void)
{
	double Golf_scores[ArrSize];
	Input(Golf_scores);
	Display(Golf_scores);
	Caculate(Golf_scores);

	system("pause");
	return 0;
}

3.下面是一个结构声明:

struct box
{
char maker [40];

float height ;

float width;

float length;

float volume ;
};
a.编写一个函数,按值传递box结构,并显示每个成员的值。
b.编写一个函数,传递box结构的地址,并将volume成员设置为其他三维长度的乘积。

c.编写一个使用这两个函数的简单程序。

#include <iostream>
using namespace std;

struct box
{
	char maker[40];
    float height;
    float width;
    float length;
    float volume;
};

//b.编写一个函数,传递box结构的地址,并将volume成员设置为其他三维长度的乘积。
void Caculate_volume(box* example)
{
    example->volume = example->length * example->width * example->height;
}
//a.编写一个函数,按值传递box结构,并显示每个成员的值。
void Display(box example)
{
    cout << "maker:  " << example.maker << endl;
    cout << "height:  " << example.height << endl;
    cout << "width:  " << example.width << endl;
    cout << "length:  " << example.length << endl;
    cout << "volume:  " << example.volume << endl;
}

int main(void)
{
    box example;
    cout << "Enter the name of maker:";
    cin.getline(example.maker, 40);
    cout << "Enter the height:";
    cin >> example.height;
    cout << "Enter the width:";
    cin >> example.width;
    cout << "Enter the length:";
    cin >> example.length;

    Caculate_volume(&example);
    Display(example);

	system("pause");
	return 0;
}

4.许多州的彩票发行机构都使用如程序清单7.4所示的简单彩票玩法的变体。在这些玩法中,玩家从一组被称为域号码(field number)的号码中选择几个。例如,可以从域号码1~47中选择5个号码;还可以从第二个区间(如1~27)选择一个号码(称为特选号码)。要赢得头奖,必须正确猜中所有的号码。中头奖的几率是选中所有域号码的几率与选中特选号码几率的乘积。例如,在这个例子中,中头奖的几率是从47个号码中正确选取5个号码的几率与从27个号码中正确选择1个号码的几率的乘积。请修改程序清单7.4,以计算中得这种彩票头奖的几率。

#include <iostream>
using namespace std;

long double probability(unsigned numbers, unsigned picks)
{
	long double result = 1.0;
	long double n;
	unsigned p;

	for (n = numbers, p = picks; p > 0; n--, p--)
	{
		result = result * n / p;
	}
	return result;
}
int main(void)
{
	double field_number = 47, field_pick = 5;
	double special_number = 27, special_pick = 1;
	
	cout << "You have one chance in "<<
	probability(field_number,field_pick)*probability(special_number,special_pick)<< 
		" of winning." << endl;
	
	system("pause");
	return 0;
}

5.定义一个递归函数,接受一个整数参数,并返回该参数的阶乘。前面讲过,3的阶乘写作3!,等于3*2!,依此类推;而0!被定义为1。通用的计算公式是,如果n大于零,则n!=n*(n-l)!。在程序中对该函数进行测试,程序使用循环让用户输入不同的值,程序将报告这些值的阶乘。

#include <iostream>
using namespace std;

long Factorial(int n)
{
	if(n == 0)     
		return 1;
	else        
		return Factorial(n - 1) * n;
}
int main(void)
{
	int n;
	cout << "Enter a number n(n>0)(q to quit):";
	while (cin>>n)
	{
		cout << n << "! = " << Factorial(n) << endl;
		cout << "Next number(q to quit): ";
	}
	system("pause");
	return 0;
}

6.编写一个程序,它使用下列函数:
Fill_array()将一个double数组的名称和长度作为参数。它提示用户输入double值,并将这些值存储到数组中。当数组被填满或用户输入了非数字时,输入将停止,并返回实际输入了多少个数字。
Show_array()将一个double数组的名称和长度作为参数,并显示该数组的内容。
Reverse-array()将一个double数组的名称和长度作为参数,并将存储在数组中的值的顺序反转。程序将使用这些函数来填充数组,然后显示数组;反转数组,然后显示数组;反转数组中除第一个和最后一个元素之外的所有元素,然后显示数组。

#include <iostream>
using namespace std;
const unsigned int ArrSize = 20;

//填充数组
int Fill_array(double Array[],unsigned int ArrSize)
{
	int i = 0;
	cout << "If you want to end the input, press the letter!" << endl;
	while (cin >> Array[i] && i < ArrSize)
	{
		i++;
	}
	return i;
}
//显示数组
void Show_array(const double Array[], int Length)
{
	for (int i = 0; i < Length; i++)
		cout << Array[i] << "   ";
	cout << endl;
}

//反转数组
void Reverse_array(double Array[], int Length)
{
	double temp;
	for (int i = 1,j = Length - 2; i < j; i++, j--)
	{
		temp = Array[i];
		Array[i] = Array[j];
		Array[j] = temp;
	}
}
int main(void)
{
	double Array[ArrSize];
	//填充数组,然后显示数组
	int Length = Fill_array(Array, ArrSize);
	Show_array(Array, Length);
	//反转数组中除第一个和最后一个元素之外的所有元素,然后显示数组。
	cout << "---------------------------------------------------" << endl;
	Reverse_array(Array, Length);
	Show_array(Array, Length);

	system("pause");
	return 0;
}

7.修改程序清单7.7中的3个数组处理函数,使之使用两个指针参数来表示区间。fill_array()函数不返回实际读取了多少个数字,而是返回一个指针,该指针指向最后被填充的位置;其他的函数可以将该指针作为第二个参数,以标识数据结尾。

#include <iostream>
using namespace std;
const int Max = 5;

double* fill_array(double* Beign, double* End);
void show_array(const double* Beign, const double* End);
void revalue(double r, double* Beign, double* End);


int main(void)
{
	double propreties[Max];
	double * End = fill_array(propreties,propreties+Max);
	show_array(propreties,End);
	if (End != propreties)
	{
		cout << "Enter revaluation factor:";
		double factor;
		while (!(cin >> factor))
		{
			cin.clear();
			while (cin.get() != '\n')
			{
				continue;
			}
			cout << "Bad input;Please enter a number:";
		}
		revalue(factor, propreties, End);
		show_array(propreties, End);
	}
	cout << "Done!" << endl;
	system("pause");
	return 0;
}
double * fill_array(double* Beign, double *End)
{
	double *temp = Beign;
	int i = 0;
	for (; temp != End; temp++)
	{
		cout << "Enter value #" << (i + 1) << ":";
		cin >> *temp;
		if (!cin)
		{
			cin.clear();
			while (cin.get() != '\n')
			{
				continue;
			}
			cout << "Bad input;Please enter a number:";
			break;
		}
		else if (*temp < 0)
		{
			break;
		}
		i++;
	}
	return temp;
}

void show_array(const double* Beign, const double* End)
{
	int i = 0;
	for (; Beign != End; Beign++)
	{
		cout << "Property #" << (i + 1) << ": $";
		cout << *Beign << endl;
		i++;
	}
}

void revalue(double r, double* Beign,  double* End)
{
	for (double* temp = Beign; temp != End; temp++)
		*temp *= r;

}

8.在不使用array类的情况下完成程序清单7.15所做的工作。编写两个这样的版本:

a.使用const char *数组存储表示季度名称的字符串,并使用double数组存储开支。
b.使用const char*数组存储表示季度名称的字符串,并使用一个结构,该结构只有一个成员———个用于存储开支的double数组。这种设计与使用array类的基本设计类似。

#include <iostream>
#include <array>
#include <string>
using namespace std;

const int Seasons = 4;
const char* Snames[4] = { "Sppring","Summer","Fall","Winter" };
void fill(double *expenses);
void show(const double expenses[], int Length);

int main(void)
{
	double expenses[Seasons];
	fill(expenses);
	show(expenses,Seasons);
	system("pause");
	return 0;
}

void fill(double* expenses)
{
	for (int i = 0; i < Seasons; i++)
	{
		cout << "Enter " << Snames[i] << " expenses:";
		cin >> expenses[i];
	}
}

void show(const double expenses[], int Length)
{
	double total = 0.0;
	cout << "\nEXPENSES\n";
	for (int i = 0; i < Seasons; i++)
	{
		cout << Snames[i] << ": $" << expenses[i] << endl;
		total += expenses[i];
	}
	cout << "Total Expenses: $" << total << endl;
}

#include <iostream>
#include <array>
#include <string>
using namespace std;
const int Seasons = 4;
struct Expenses
{
	double expenses[Seasons];
};

const char* Snames[4] = { "Sppring","Summer","Fall","Winter" };
void fill(struct Expenses * e);
void show(const Expenses *ptr);

int main(void)
{
	Expenses e;
	fill(&e);
	show(&e);
	system("pause");
	return 0;
}

void fill(struct Expenses* ptr)
{
	for (int i = 0; i < Seasons; i++)
	{
		cout << "Enter " << Snames[i] << " expenses:";
		cin >> ptr->expenses[i];
	}
}

void show(const Expenses *ptr)
{
	double total = 0.0;
	cout << "\nEXPENSES\n";
	for (int i = 0; i < Seasons; i++)
	{
		cout << Snames[i] << ": $" << ptr->expenses[i] << endl;
		total += ptr->expenses[i];
	}
	cout << "Total Expenses: $" << total << endl;
}

9.这个练习让您编写处理数组和结构的函数。下面是程序的框架,请提供其中描述的函数,以完成该程序。
#include <iostream>

using namespace std;

const int SLEN = 30;

struct student {
char fullname [SLEN];

char hobby [SLEN];

int ooplevel;
};
//getinfo () has two arguments: a pointer to the first element of

//an array of student structures and an int representing the

// number of elements of the array. The function solicits and

//stores data about students. It terminates input upon filling

//the array or upon encountering a blank line for the student

//name.The function returns the actual number of array elements

//filled.
int getinfo(student pa [] , int n) ;
//display1 ( ) takes a student structure as an argument

//and displays its contents
void display1(student st) ;
// display2 () takes the address of student structure as an

//argument and displays the structure's contents
void display2 (const student * ps) ;
//display3 () takes the address of the first element of an array

//of student structures and the number of array elements as
//arguments and displays the contents of the structures

void display3 (const student pa [] , int n) ;
int main ()
cout << "Enter class size: ";

int class_size;
cin >> class_size;

while(cin.get  != '\n')
continue;
student * ptr_stu = new student [class_size] ;
int entered = getinfo(ptr_stu, class_size) ;

for (int i =0; i < entered; i++)

{
display1(ptr_stu[i]);

display2 (&ptr_stu[i]);

}
display3 (ptr-stu,  entered);

delete [] ptr_stu;
cout <<"Done\n" ;
return  0 ;

#include <iostream>
using namespace std;
const int SLEN = 30;

struct student {
	char fullname[SLEN];
    char hobby[SLEN];
    int ooplevel;
};


int getinfo(student pa[], int n)
{
	cout << "Please input the students information:" << endl;
	int i;
	for (i = 0; i < n; i++)		
	{
		cout << "Student #" << i + 1 << ": " << endl;
		cout << "Fullname: ";
		cin.getline(pa[i].fullname, SLEN);		
		if (pa[i].fullname[0] == '\0')		        
			break;
		cout << "Hobby: ";
		if (pa[i].hobby[0] == '\0')
			break;
		cin.getline(pa[i].hobby, SLEN);		
		cout << "Ooplevel: ";
		if (!(cin >> pa[i].ooplevel))
			break;
		cin.get();			
	}
	cout <<"Enter End!"<< endl;
	return i;		//返回实际获取到的元素的数量
}


void display1(student st)
{
	cout << "fullname:" << st.fullname << "     hobby:" << st.hobby <<
		"    opplevel:" << st.ooplevel << endl;
}
// display2 () takes the address of student structure as an
//argument and displays the structure's contents
void display2(const student* ps)
{
	cout << "fullname:" << ps->fullname << "     hobby:" << ps->hobby <<
		"    opplevel:" << ps->ooplevel << endl;
}
//display3 () takes the address of the first element of an array
//of student structures and the number of array elements as
//arguments and displays the contents of the structures
void display3(const student pa[], int n)
{
	for (int i = 0; i < n; i++)
	{
		cout << "Student #" << i + 1 << endl;
		cout << "fullname:" << pa[i].fullname << "     hobby:" << pa[i].hobby <<
			"    opplevel:" << pa[i].ooplevel << endl;
	}
}
int main()
{
	cout << "Enter class size: ";
	int class_size;
	cin >> class_size;
	while (cin.get()!= '\n')
		continue;
	student* ptr_stu = new student[class_size];
	int entered = getinfo(ptr_stu, class_size);

	for (int i = 0; i < entered; i++)
	{
		display1(ptr_stu[i]);
		display2(&ptr_stu[i]);
	}
	display3(ptr_stu, entered);

	delete[] ptr_stu;
	cout << "Done\n";
	return  0;
}

10.设计一个名为calculate()的函数,它接受两个double值和一个指向函数的指针,而被指向的函数接受两个double参数,并返回一个double 值。calculate()函数的类型也是double,并返回被指向的函数使用calculate()的两个double参数计算得到的值。例如,假设add()函数的定义如下:
double add (double x, double y)
return x+ y;
则下述代码中的函数调用将导致calculate()把2.5和10.4传递给add( )函数,并返回add()的返回值(12.9):
double q = calculate(2.5, 10.4,  add);
请编写一个程序,它调用上述两个函数和至少另一个与add()类似的函数。该程序使用循环来让用户成对地输入数字。对于每对数字,程序都使用calculate( )来调用add( )和至少一个其他的函数。如果读者爱冒险,可以尝试创建一个指针数组,其中的指针指向add()样式的函数,并编写一个循环,使用这些指针连续让 calculate()调用这些函数。提示:下面是声明这种指针数组的方式,其中包含三个指针:.
double (*pf [3] )(double, double);
可以采用数组初始化语法,并将函数名作为地址来初始化这样的数组。

#include <iostream>
using namespace std;

double add(double x, double y);
double subtract(double x, double y);
double multiply(double x, double y);
double caculate(double x, double y, double (*func)(double, double));
int main(void)
{
    double x;
    double y;
    double (*pf[3])(double, double) = {add,subtract,multiply};//指针数组
    cout << "Enter two numbers(q to quit):" ;
    while (cin >> x >> y)
    {
        for (int i = 0; i < 3; i++)
        {
            cout << "The result #" << i + 1 << ":" << caculate(x, y,pf[i]) << endl;

        }
        cout << "Enter two numbers(q to quit):" << endl;
    }
	system("pause");
	return 0;
}
double add(double x, double y)
{
    return x + y;
}

double subtract(double x, double y)
{
    return x - y;
}

double multiply(double x, double y)
{
    return x * y;
}

double caculate(double x, double y, double (*func)(double, double))
{
    return (*func)(x, y);
}

第8章 函数探幽

1.编写通常接受一个参数(字符串的地址),并打印该字符串的函数。然而,如果提供了第二个参数(int类型),且该参数不为0,则该函数打印字符串的次数将为该函数被调用的次数(注意,字符串的打印次数不等于第二个参数的值而等于函数被调用的次数)。是的,这是一个非常可笑的函数,但它让您能够使用本章介绍的一些技术。在一个简单的程序中使用该函数,以演示该函数是如何工作的。

解:使用默认参数。

#include <iostream>

const int Len = 20;

void print(char* str, int a = 0);
using namespace std;
int main(void)
{
	char str[Len] = "abcdefg" ;
	print(str);
	cout << endl;
	print(str);
	cout << endl;
	print(str,10);
	cout << endl;
	print(str,30);
	cout << endl;


	system("pause");
	return 0;
}
void print(char* str, int n)
{
	static int count = 0;       
	count++;
	while (n >= 0)
	{
		if (n == 0)
		{
			cout << str << endl;
			return;
		}
		else
		{
			for (int i = 0; i < count; i++)
			{
				cout << str << endl;
			}
			return;
		}
	}
}


2. CandyBar结构包含3个成员。第一个成员存储candy bar的品牌名称;第二个成员存储candy bar的重量(可能有小数);第三个成员存储candy bar的热量(整数)。 请编写一个程序,它使用一个这样的函数,即将CandyBar的引用、char指针、double和int作为参数,并用最后3个值设置相应的结构成员,最后3个参数的默认值分别为“Millennijum  Munch "、2.85和350。另外,该程序还包含一个以 CandyBar 的引用为参数,并显示结构内容的函数。请尽可能使用const。

 答:笔记://x.brand = a;        //如果brand是string,这里可以直接赋值
        strcpy_s(x.brand,a);    //如果brand是char[],字符串不能直接赋值,需要进行strcpy拷贝

  这里出错好久才明白。

#include <iostream>
#include <string>
using namespace std;
const int Len = 30;

struct CandyBar
{
	char brand[Len];
	double weight;
	int calories;
};
void fill_candybar(CandyBar& x, const char* a= "Millennijum  Munch ", const double b = 2.85, const int c = 350);
void Display(const CandyBar& s);
int main(void)
{

	CandyBar candy1, candy2,candy3;	
	fill_candybar(candy1);
	cout << "candy1: "<< endl;
	Display(candy1);

	const char* m = new char[Len];
	m= "Dove";
	fill_candybar(candy2, m, 3.30, 300);	//baby使用自定义参
	cout << "candy2: " << endl;
	Display(candy2);

	const char* s = new char[Len];
	s = "Margaret";
	fill_candybar(candy3, s, 4.28, 900);	//baby使用自定义参
	cout << "candy3: " << endl;
	Display(candy3);

	system("pause");
	return 0;
}
void fill_candybar(CandyBar &x,const char* a,const double b,const int c)
{

	//x.brand = a;        //如果brand是string,这里可以直接赋值
	strcpy_s(x.brand,a);    //如果brand是char[],字符串不能直接赋值,需要进行strcpy拷贝
	x.weight = b;
	x.calories = c;
}
void Display(const CandyBar& s)
{
	cout << "Brand:" << s.brand << endl;
	cout << "Weight:" << s.weight << endl;
	cout << "Calories:" << s.calories << endl;
}


3. 编写一个函数,它接受一个指向string对象的引用作为参数“并将该string对象的内容转换为大写,为此可使用表6.4描述的函数 toupper()。然后编写一个程序,它通过使用一个循环让您能够用不同的输入来测试这个函数,该程序的运行情况如下:
Enter a string (q to quit) : go away

GO AWAY
Next string (q to quit) : good grief!

GOOD GRIEF!
Next string (q to quit): q

Bye.

笔记:a.size()可以得到string类字符串a的长度。sizeof()只能得到字符数组长度。

#include <iostream>
#include <cctype>
#include <string>
using namespace std;
string upper(string& a);
int main(void)
{
	string a;
	cout << "Enter a string (q to quit) :";
	getline(cin, a);
	while (a != "q")
	{
		cout << upper(a) << endl;
		cout << "Next string (q to quit) :";
		getline(cin, a);
	}
	cout << "Bye." << endl;
	system("pause");
	return 0;
}
string upper(string &a)
{
	for (int i = 0; i < a.size(); i++)
	{
		a[i] = toupper(a[i]);
	}
	return a;
}

4.下面是一个程序框架

#include<iostream>

using namespace std;

#include<cstring>       //for strlen(),strcpy()

struct stringy {

char * str; //points to a string

int ct; //length of string (not couting '\0')

};

// prototypes for set(), show(), and show() go here

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!");

return 0;

}

请提供其中描述的函数和原型,从而完成该程序。注意,应有两个 show ()函数,每个都使用默认参数。请尽可能的使用 const 参数。 set() 使用 new 分配足够的空间来存储定指的字符串。这里使用的技术与设计和实现类使用的相似。(可能还必须修改头文件的名称,删除 using 编译指令,这取决于所用的编译器。)

笔记://三个参数时:strcpy_s( strDestination,size_t numberOfElements,const char* strSource);
        //两个参数时:strcpy (char(&strDestination)[size],const char* strSource);
       //使用3个参数的版本时,一般的做法就是将长度定为被复制的字符串长度 + 1

形参是指针,直接打印名称就能打印出字符串。

void show(const stringy& a ){
        cout << a.str << endl;}
}

void show(const char* a, int b){
        cout << a<<endl;}

#include<iostream>
using namespace std;
#include<string>       //for strlen(),strcpy()

struct stringy 
{
	char* str;           //points to a string
	int ct;              //length of string (not couting '\0')
};

// prototypes for set(), show(), and show() go here
void set(stringy &beany, const char * testing);
void show(const stringy &a, int b = 1);
void show(const char* a, int b = 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!");

	return 0;

}
void set(stringy& beany, const char* testing)
{
	beany.ct = strlen(testing) + 1;
	beany.str = new char[beany.ct];
	strcpy_s(beany.str,beany.ct,testing);   //这里编译器要求strcpy_s版本
		//三个参数时:strcpy_s( strDestination,size_t numberOfElements,const char* strSource);
        //两个参数时:strcpy (char(&strDestination)[size],const char* strSource);
       //使用3个参数的版本时,一般的做法就是将长度定为被复制的字符串长度 + 1
		
}
void show(const stringy& a, int b )
{
	for (int i = 0; i < b; i++)
	{
		cout << a.str << endl;
	}
}
void show(const char* a, int b)
{
	for (int i = 0; i < b; i++)
	{
		cout << a<<endl;
	}
}

5. 编写模板函数 max5 (),它将一个包含 5 个 T 类型元素的数组作为参数,并返回数组中最大的元素(由于长度固定,因此可以在循环中使用硬编码,而不必通过参数来传递)。在一个程序中使用该函数,将 T 替换为一个包含 5 个 int 值的数组和一个包含 5 个 double 值的数组,以测试该函数。

#include <iostream>
using namespace std;

template <typename T>
T max5(T arr[]);
int main(void)
{
	int a[5] = { 1,6,3,2,5 };
	double b[5] = { 1.20,2.30,5.2,1.4,2.7 };

	int c = max5(a);
	double d = max5(b);

	cout << "int数组中最大值为:" << c << endl;
	cout << "double数组中最大值为:" << d << endl;

	system("pause");
	return 0;
}
template <typename T>
T max5(T arr[])
{
	T temp = arr[0];
	for (int i = 1; i < 5; i++)
	{
		if (arr[i] > temp)
			temp = arr[i];
	}
	return temp;
}

6. 编写模板函数 maxn (),它将由一个 T 类型元素组成的数组和一个表示数组元素数目的整数作为参数,并返回数组中最大的元素。在程序对它进行测试,该程序使用一个包含 6 个 int 元素的数组和一个包含 4 个 double 元素的数组来调用该函数。程序还包含一个具体化,它将 char 指针数组和数组中的指针数量作为参数,并返回最长的字符串的地址。如果有多个这样的字符串,则返回其中第一个字符串的地址。使用由 5 个字符串指针组成的数组来测试该具体化。

#include <iostream>
#include <string>
using namespace std;

template <typename T>
T maxn(T* arr, const int n);

//具体化
template<> const char* maxn(const char* arr[], const int n);

int main(void)
{
	int    a[6] = { 4,6,3,5,8,2 };
	double b[4] = { 2.3,5.4,1.3,6.2 };

	int c = maxn(a,sizeof(a)/sizeof(int));
	double d = maxn(b, sizeof(b) / sizeof(double));

	cout << "int数组中最大值为:" << c << endl;
	cout << "double数组中最大值为:" << d << endl;

	const char* arr[7] = { "absaihc","chuahuiap","asjch cnck c","csamkc casj","fwef","a","bc" };
    const char* f = maxn(arr, 7) ;
	cout << f << endl;
	system("pause");
	return 0;
}
template <typename T>
T maxn(T* arr, const int n)
{
	T temp = arr[0];
	for (int i = 1; i < n; i++)
	{
		if (arr[i] > temp)
		{
			temp = arr[i];
		}
	}
	return temp;
}
template<> const char* maxn(const char* arr[], const int n)
{
	const char* temp = arr[0];

	for (int i = 1; i < n; i++)
	{
		if (strlen(arr[i]) > strlen(temp))
			temp = arr[i];
	}
	;
	return temp;
}

7. 修改程序清单 8.14 ,使其使用两个名为 SumArray ()的模板函数来返回数组元素的总和,而不是显示数组的内容。程序应显示thing的总和以及所有 debt 的总和。

#include <iostream>
using namespace std;

template<typename T>
T SumArray(T arr[], int n);    //template A

template<typename T>                  //template B
T SumArray(T* arr[], int n);

struct debts
{
	char name[50];
	double amouunt;
};

int main(void)
{
	int things[6] = { 13,31,103,301,310,130 };
	struct debts me_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] = &me_E->amouunt;

	cout << "Listing Mr.E's counts:" << endl;
	cout << SumArray(things, 6) << endl;

	cout << "Listing Mr.E's debts:" << endl;
	cout << SumArray(pd, 3) << endl;

	system("pause");
	return 0;
}
template<typename T>
T SumArray(T arr[], int n)
{
	T sum = 0;
	cout << "template A" << endl;
	for (int i = 0; i < n; i++)
		sum += arr[i];
	return sum;
}
template<typename T>                  //template B
T SumArray(T* arr[], int n)
{
	T sum = 0;
	cout << "template B" << endl;
	for (int i = 0; i < n; i++)
		sum += *arr[i];
	return sum;
}

第9章 内存模型和名称空间

1. 下面是一个头文件:

(…………)

注意到setgolf()被重载,可以这样使用其第一个版本:

golf ann;

setgolf(ann, "Ann Birdfree", 24);

上述函数调用提供了存储在ann结构中的信息。可以这样使用其第二个版本:

golf andy;

setgolf(andy);

上述函数将提示用户输入姓名和等级,并将它们存储在andy结构中。这个函数可以(但是不一定必须)在内部使用第一个版本。

根据这个头文件,创建一个多文件程序。其中的一个文件名为golf.cpp,它提供了与头文件中的原型匹配的函数定义;另一个文件应包含main(),并演示原型化函数的所有特性。例如,包含一个让用户输入的循环,并使用输入的数据来填充一个由golf结构组成的数组,数组被填满或用户将高尔夫选手的姓名设置为空字符串时,循环将结束。main()函数只使用头文件中原型化的函数来访问golf结构。

头文件 golf.h

#include <iostream>
using namespace std;
const int Len = 40;

struct golf
{
	char fullname[Len];
	int handicap;
};

void setgolf(golf& g, const char* name, int hc);
int setgolf(golf& g);
void handicap(golf& g, int hc);
void showgolf(const golf& g);

golf.cpp(函数定义)

#include "golf.h"
#include <iostream>
#include <cstring>
using namespace std;

void setgolf(golf &g, const char* name, int hc)
{
	strcpy_s(g.fullname, name);
	g.handicap = hc;
}

int setgolf(golf& g)
{
	cout << "Please enter the full name of player:";
	cin.getline(g.fullname, Len);
	if (strcmp(g.fullname, "") == 0)
	{
			return 0;
	}

	cout << "Please enter the handicap of player:";
	cin >> g.handicap;
	cin.get();
	return 1;
}

void handicap(golf& g, int hc)
{
	g.handicap = hc;
}

void showgolf(const golf& g)
{
	cout << "Information:" << endl;
	cout << "Name: " << g.fullname << endl;
	cout << "handicap: " << g.handicap << endl;
}

main.cpp主函数

#include "golf.h"
#include <iostream>
using namespace std;

int main(void)
{
	golf ann;
	setgolf(ann, "Ann Birdfree", 24);
	showgolf(ann);

	golf andy;
	setgolf(andy);
	showgolf(andy);
	handicap(andy, 30);
	showgolf(andy);

	system("pause");
	return 0;
}

 测试结果

2. 修改程序清单9.9:用string对象代替字符数组。这样,该程序将不再需要检查输入的字符串是否过长,同时可以将输入字符串同字符串“”进行比较,以判断是否为空行。

#include <iostream>
#include <string>
using namespace std;
void strcount(const string str);
int main(void)
{
	string input;

	cout << "Enter a line:" << endl;
	getline(cin, input);
	while (cin)
	{
		strcount(input);
		cout << "Enter next line (empty line to quit):\n";
		getline(cin, input);
		if (input == "")
			break;
	}
	cout << "Bye." << endl;

	system("pause");
	return 0;
}

void strcount(const string str)
{
	static int total = 0;
	int count = 0;
	cout << "\"" << str << "\" contains ";
	while (str[count])
		count++;
	total += count;
	cout << count << " characters\n";
	cout << total << " characters in total\n";
}

3. 下面是一个结构声明:

struct chaff

{

       char dross[20];

        int slag;

};

编写一个程序,使用定位new运算符将一组放个包含两个这种结构的数组在一个缓冲区中。然后,给结构的成员赋值(对于char数组,使用函数strcpy()),并使用一个循环来显示内容。一种方法是像程序清单9.10那样将一个静态数组用作缓冲区;另一种方法是使用常规new运算符来分配缓冲区。

方法一:定位运算符

#include <iostream>
#include <string>
#include <new>
using namespace std;
const int BUF = 512;
char buffer[BUF];

struct chaff
{
	char dross[20];
	int slag;
};
int main(void)
{
	chaff * p = new(buffer) chaff[2];
	char dross[20];
	for (int i = 0; i < 2; i++)
	{
		cout << "Enter dross of #" << i + 1 << " chaff:\n";
		cin.getline(dross, 20);
		strcpy_s(p[i].dross, dross);
		cout << "Enter slag of #" << i + 1 << " chaff:\n";
		cin >> p[i].slag;
		cin.get();
	}

	for (int i = 0; i < 2; i++)
	{
		cout << "chaff #" << i + 1 << ":\n";
		cout << "dross: " << p[i].dross << "      slag: " << p[i].slag << endl;
	}

	system("pause");
	return 0;
}

方法二:常规new运算符

#include <iostream>
#include <string>
using namespace std;

struct chaff
{
	char dross[20];
	int slag;
};
int main(void)
{
	chaff* p = new chaff[2];
	char dross[20];
	for (int i = 0; i < 2; i++)
	{
		cout << "Enter dross of #" << i + 1 << " chaff:\n";
		cin.getline(dross, 20);
		strcpy_s(p[i].dross, dross);
		cout << "Enter slag of #" << i + 1 << " chaff:\n";
		cin >> p[i].slag;
		cin.get();
	}

	for (int i = 0; i < 2; i++)
	{
		cout << "chaff #" << i + 1 << ":\n";
		cout << "dross: " << p[i].dross << "      slag: " << p[i].slag << endl;
	}

	delete []p;
	system("pause");
	return 0;
}

4. 请基于下面这个名称空间编写一个由3个文件组成的程序:

(…………)

第一个文件是一个头文件,其中包含名称空间;第二个文件是一个源代码文件,它对这个名称空间进行扩展,以提供这三个函数的定义;第三个文件声明两个Sales对象,并使用setSales()的交互式版本为一个结构提供值,然后使用setSales()的非交互式版本为另一个结构提供值。另外它还使用showSales()来显示这两个结构的内容。

解答:

  1. 对名称空间进行扩展,以提供三个函数的定义。(书p332)在名称空间中声明的函数名的作用域为整个名称空间,因此定义和声明必须位于同一名称空间中。通过包含头文件可以导入原来的名称空间。然后在文件中将函数定义添加到名称空间中。
  2. 在main函数中包含名称空间使用using编译指令即可。using namespace SALES;

头文件9.4.h

#include <iostream>
namespace SALES
{
	const int QUARTERS = 4;
	struct Sales
	{
		double sales[QUARTERS];
		double average;
		double max;
		double min;
	};


	void setSales(Sales& s, const double ar[], int n);
	void setSales(Sales& s);
	void showSales(const Sales& s);
}

函数定义.cpp

#include "9.4.h"
#include <iostream>
using namespace std;
namespace SALES
{

	void setSales(Sales& s, const double ar[], int n)   //非交互式版本
	{
        if (n < 4)
        {
            for (int i = 0; i < n; i++)
            {
                s.sales[i] = ar[i];
            }
            for (int j = n; j < 4; j++)
            {
                s.sales[j] = 0;
            }
        }
        else
        {
            for (int i = 0; i < 4; i++)
            {
                s.sales[i] = ar[i];
            }
        }
        s.average = (s.sales[0] + s.sales[1] + s.sales[2] + s.sales[3]) / 4;
        double max = 0.0;
        double min = 1000000;
        for (int i = 0; i < 4; i++)
        {
            if (s.sales[i] > max)
            {
                max = s.sales[i];
            }
            if (s.sales[i] < min)
            {
                min = s.sales[i];
            }
        }
        s.max = max;
        s.min = min;

	}
    void setSales(Sales& s)
    {
        cout << "Please enter sales:\n";
        for (int i = 0; i < 4; i++)
        {
            cout << "The #" << i + 1 << " quarter is: ";
            cin >> s.sales[i];
        }
        s.average = (s.sales[0] + s.sales[1] + s.sales[2] + s.sales[3]) / 4;
        double max = 0.0;
        double min = 1000000;
        for (int i = 0; i < 4; i++)
        {
            if (s.sales[i] > max)
            {
                max = s.sales[i];
            }
            if (s.sales[i] < min)
            {
                min = s.sales[i];
            }
        }
        s.max = max;
        s.min = min;
    }

    void showSales(const Sales& s)
    {
        cout << "The sales of 4 quarters are $" << s.sales[0] << ", $" << s.sales[1] << ", $" << s.sales[2] << ", $" << s.sales[3] << endl;
        cout << "Average:" << s.average << endl;
        cout << "Max:" << s.max << endl;
        cout << "Min:" << s.min << endl;
    }

}

main函数.cpp

#include "9.4.h"
#include <iostream>
using namespace std;
using namespace SALES;

int main(void)
{
	Sales s1, s2;
    cout << "#1:" << endl;
    setSales(s1);
    showSales(s1);
    cout << "--------------------------------------------------" << endl;
    cout << "#2"<<endl;
    double ar[3] = { 10,20,30 };
    setSales(s2, ar, 3);
    showSales(s2);
    cout << "Bye\n";

	system("pause");
	return 0;
}

第10章 对象和类

(为节约时间,使用类的程序只写了简单的测试,未循环写入、未考虑交互性等)

1. 为复习题5描述的类提供方法定义,并编写一个小程序来演示所有的特性。
   复习题5:
   定义一个类来表示银行账户。数据成员包括储户姓名、账号(使用字符串)和存款。成员函数执行如下操作:
   ·创建一个对象并将其初始化
   ·显示储户姓名、账号和存款
   ·存入参数指定的存款
   ·取出参数指定的款项

1.1. 头文件bank.h

#ifndef BANK_H_
#define BANK_H_
#include <iostream>
#include <string>
using namespace std;
class BankAccount
{
private:
	string m_name;
	string m_acctnum;
	double m_balance;
public:
	BankAccount();               //默认构造函数
	BankAccount(const string &cilent, const string & num, double bal );
	void show(void) const;         //显示
	void deposit(double crash);       //存
	void withdraw(double crash);       //取

};

#endif // !10.1_H_s

1.2.定义成员函数.cpp

#include "bank.h"
#include <iostream>
#include <string>
using namespace std;

BankAccount::BankAccount()
{
	m_name = "None";
	m_acctnum = "None";
	m_balance = 0.0;
}
BankAccount::BankAccount(const string &cilent, const string &num, double bal )
{
	m_name = cilent;
	m_acctnum = num;
	m_balance = bal;

}
void BankAccount::show(void) const
{
	cout << "Account information:" << endl;
	cout << "Name: " << m_name << endl;
	cout << "Account number: " << m_acctnum << endl;
	cout << "Balance: " << m_balance << endl;
}
void BankAccount::deposit(double crash)
{
	m_balance += crash;
}
void BankAccount::withdraw(double crash)
{
	m_balance -= crash;
}

1.3.使用类.cpp

#include "bank.h"
#include <iostream>
#include <string>

int main(void)
{
	//使用默认构造函数创建账户bank1
	string name1;
	string accountnum1;
	double bal1;
	double add, minus;
	BankAccount bank1 = BankAccount();            //使用默认构造函数
	bank1.show();
	cout << "Enter name:";
	getline(cin, name1);
	cout << "Enter the number of account:";
	getline(cin, accountnum1);
	cout << "Enter balance:";
	cin >> bal1;
	cin.get();
	bank1 = BankAccount(name1, accountnum1, bal1);      //使用构造函数
	bank1.show();
	cout << "Please enter the amount to deposit:";
	cin >> add;
	bank1.deposit(add);
	bank1.show();
	cout << "Please input the amount to be withdrawn:";
	cin >> minus;
	bank1.withdraw(minus);
	bank1.show();

	system("pause");
	return 0;
}

总结:我把头文件命名成10.1.h会出错 ,换成英文命名就正常了。

2. 下面是一个非常简单的类定义
class Person
{
private:
    static const int LIMIT = 25;
    string lname;                     // Person’s last name
    char fname[LIMIT];            // Person’s first name
public:
    Person() {lname = ""; fname[0] = '\0';}                    // #1
    Person(const string & ln, const char * fn = "Heyyou");      // #2
    // the following methods display lname and fname
    void Show() const;        // firstname lastname format
    void FormalShow() const;  // lastname, firstname format
};
它使用了一个string对象和一个字符数组,让您能够比较它们的用法。请提供未定义的方法的代码,以完成这个类的实现。
再编写一个使用这个类的程序,它使用了三种可能的构造函数的调用(没有参数、一个参数和两个参数)以及两种显示方法。
下面是一个使用这些构造函数和方法的例子:
    Person one;                        // use default constructor
    Person two("Smythecraft");         // use #2 with one default argument
    Person three("Dimwiddy", "Sam");   // use #2, no defaults one.Show();
    cout << endl;
    one.FormalShow();
    // etc. for two and three

2.1.头文件person.h

#ifndef PERSON_H_
#define PERSON_H_
#include <iostream>
using namespace std;

class Person
{
private:
	static const int LIMIT = 25;
	string lname;
	char fname[LIMIT];
public:
	Person() { lname = ""; fname[0] = '\0'; };
	Person(const string& ln, const char* fn = "Heyyou");
	void Show()const;
	void FormalShow()const;
};
#endif // !10.2_H_

 2.2.成员函数.cpp

#include "person.h"
#include <iostream>
using namespace std;
Person::Person(const string& ln, const char* fn )  //默认参数在原型时有即可,定义时不需要有
{
	lname = ln;
	strcpy_s(fname, LIMIT, fn);
}
void Person::Show()const
{
	cout << fname << "  " << lname << endl;
}
void Person::FormalShow()const
{
	cout << lname << " , " << fname << endl;
}

2.3.使用类.cpp

#include "person.h"
#include <iostream>

int main(void)
{
	Person one;
	cout << "默认构造one:" << endl;
	one.Show();
	one.FormalShow();

	Person two("Smythecraft");
	cout << "two显示如下:" << endl;
	two.Show();
	two.FormalShow();

	Person three("Dimwiddy", "Sam");
	cout << "three显示如下:" << endl;
	three.Show();
	three.FormalShow();

	system("pause");
	return 0;
}

总结:含有默认参数的函数只有在函数原型时写,函数定义时不用,会出错。

3. 完成第9章的编程练习1,但要用正确的golf类声明替换那里的代码。用带合适参数的构造函数替换setgolf(golf&, const char*, int),以提供初始值。保留setgolf()的交互版本,但要用构造函数来实现它(例如,setgolf()的代码应该获得数据,将数据传递给构造函数来创建一个临时对象,并将其赋给调用对象,即*this)。
3.1.头文件golf10.h

#ifndef GOLF_H_
#define GOLF_H_

#include <iostream>
using namespace std;

class Golf
{
private:
	static const int Len = 40;
	char m_fullname[Len];
	int m_handicap;
public:
	Golf(const char* name, int hc);
	Golf();
	void sethandicap(int hc);
	void showgolf( );

};

#endif // !GOLF_H_

3.2.成员函数定义.cpp

#include "golf10.h"
#include <iostream>
#include <cstring>
using namespace std;
Golf::Golf(const char* name, int hc)
{
	strcpy_s(m_fullname, name);
	m_handicap = hc;
}
Golf::Golf()
{
	char t_name[Len];
	int  t_handicap;
	cout << "Please enter the fullname of player:";
	cin.getline(t_name, Len);
	cout << "Please enter the handicap of player:";
	cin >> t_handicap;
	cin.get();
	*this = Golf(t_name, t_handicap);
}
void Golf::sethandicap(int hc)
{
	m_handicap = hc;
}
void Golf::showgolf()
{
	cout << "Information:" << endl;
	cout << "Name: " << m_fullname << endl;
	cout << "handicap: " << m_handicap << endl;
}

3.3.使用类.cpp

#include "golf10.h"
#include <iostream>
using namespace std;

int main(void)
{
	golf g1;
	g1.showgolf();
	g1.sethandicap(100);
	g1.showgolf();

	golf g2("li hua", 99);
	g2.showgolf();
	g2.sethandicap(100);
	g2.showgolf();

	system("pause");
	return 0;
}

 4.完成第九章编程练习4,但将Sales结构及相关的函数转换为一个类及其方法。用构造函数替换setSales(sales&, double[], int)函数。 用构造函数实现setSales(Sales&)方法的交互版本。将类保留在名称空间SALES中。

4.1.头文件sales.h

#ifndef SALES10_H_
#define SALES_H_
#include <iostream>
namespace SALES
{
	class Sales
	{
	private:
		static const int QUARTERS = 4;
		double m_sales[QUARTERS];
		double m_average;
		double m_max;
		double m_min;
	public:
		Sales(const double ar[], int n);
		Sales();
		void showSales();

	};
}
#endif // !SALES10_H_

4.2.成员函数定义.cpp

#include "sales10.h"
#include <iostream>
using namespace std;
namespace SALES
{
    Sales::Sales(const double ar[], int n)
    {
        if (n < 4)
        {
            for (int i = 0; i < n; i++)
            {
                m_sales[i] = ar[i];
            }
            for (int j = n; j < 4; j++)
            {
                m_sales[j] = 0;
            }
        }
        else
        {
            for (int i = 0; i < 4; i++)
            {
                m_sales[i] = ar[i];
            }
        }
        m_average = (m_sales[0] + m_sales[1] + m_sales[2] + m_sales[3]) / 4;
        double max = 0.0;
        double min = 1000000;
        for (int i = 0; i < 4; i++)
        {
            if (m_sales[i] > max)
            {
                max = m_sales[i];
            }
            if (m_sales[i] < min)
            {
                min = m_sales[i];
            }
        }
        m_max = max;
        m_min = min;
    }
    Sales::Sales()
    {
        cout << "Please enter sales:\n";
        for (int i = 0; i < 4; i++)
        {
            cout << "The #" << i + 1 << " quarter is: ";
            cin >> m_sales[i];
        }
        m_average = (m_sales[0] + m_sales[1] + m_sales[2] + m_sales[3]) / 4;
        double max = 0.0;
        double min = 1000000;
        for (int i = 0; i < 4; i++)
        {
            if (m_sales[i] > max)
            {
                max = m_sales[i];
            }
            if (m_sales[i] < min)
            {
                min = m_sales[i];
            }
        }
        m_max = max;
        m_min = min;
    }
    

    void Sales::showSales()
    {
        cout << "The sales of 4 quarters are $" << m_sales[0] << ", $" << m_sales[1] << ", $" << m_sales[2] << ", $" << m_sales[3] << endl;
        cout << "Average:" << m_average << endl;
        cout << "Max:" << m_max << endl;
        cout << "Min:" << m_min << endl;
    }

}

4.3.使用类.cpp

#include "sales10.h"
#include <iostream>
using namespace std;
using namespace SALES;

int main(void)
{

	Sales s1;
    cout << "#1:" << endl;
    s1.showSales();
    cout << "--------------------------------------------------" << endl;
    cout << "#2"<<endl;
    double ar[3] = { 10,20,30 };
    Sales s2 = Sales( ar, 3);
    s2.showSales();
    cout << "Bye\n";

	system("pause");
	return 0;
}

5. 考虑下面的结构声明:
struct customer{
    char fullname[35];
    double payment;
};
编写一个程序,它从栈中添加和删除customer结构(栈用Stack类声明表示)。每次customer结构被删除时,其payment的值都将被加入到总数中,并报告总数。
注意:应该可以直接使用Stack类而不作修改;只需修改typedef声明,使Item的类型为customer,而不是unsigned long即可。
5.1.头文件stack.h

#ifndef STACK10_H_
#define STACK10_H_
#include <iostream>
struct customer 
{
    char fullname[35];
    double payment;
};
typedef customer Item;
class Stack
{
private:
    enum{MAX = 10};
    Item items[MAX];
    int top;
public:
    Stack();
    bool isempty() const;
    bool isfull() const;
    bool push(const Item& item);
    bool pop(Item& item);
};
#endif // !STACK_H_

5.2.成员函数定义.cpp

#include "stack10.h"
Stack::Stack()
{
	top = 0;
}
bool Stack::isempty() const
{
	return top == 0;
}
bool Stack::isfull() const
{
	return top == MAX;
}

bool Stack::push(const Item& item)
{
	if (top < MAX)
	{
		items[top++] = item;
		return true;
	}
	else
		return false;
}

bool Stack::pop(Item& item)
{
	if (top > 0)
	{
		item = items[--top];
		return true;
	}
	else
		return false;
}

5.3使用类.cpp

#include <iostream>
#include <cctype>
#include "stack10.h"
using namespace std;

int main(void)
{
	Stack st;
	char ch;
	customer po;
	double totalpayment = 0.0;
	cout << "Please enter A to add a purchase order," << endl;
	cout << "P to process a PO,or Q to quit." << endl;
	while (cin >> ch && toupper(ch) != 'Q')
	{
		while (cin.get() != '\n')
			continue;
		if (!isalpha(ch))
		{
			cout << "\a";
			continue;
		}
		switch (ch)
		{
		case'A':
		case 'a':
			cout << "Enter the name of customer:";
			cin.getline(po.fullname,30);
			cout << "Enter the payment: ";
			cin >> po.payment;
			cin.get();
			if (st.isfull())
				cout << "Stack aleady full" << endl;
			else
				st.push(po);
			break;

		case 'P':
		case 'p':
			if (st.isempty())
				cout << "stack aleady empty" << endl;
			else
			{
				totalpayment += po.payment;
				st.pop(po);
				cout << "PO #" << po .fullname<< "  popped" << endl;
			}
			break;
		}
		cout << "Please enter A to add a purchase order," << endl;
		cout << "P to Process a PO,or Q to quit." << endl;
	}
	cout << "Bye!" << endl;
	return 0;
}

6. 下面是一个类声明:
class Move
{
private:
    double x;
    double y;
public:
    Move(double a = 0, double b = 0);       // sets x, y to a, b
    showmove() const;                       // shows current x,y values
    Move add(const Move & m) const;
// this function adds x of m to x of invoking object to get new x,
// adds y of m to y of invoking object to get new y, creates a new
// move object initialized to new x, y values and returns it
//此函数将m的x加到调用对象的x以获取新的x,将m的y添加到调用对象的y中以获得新的y,
//创建一个新的对象,并将对象初始化为新的x,y值并返回它
    reset(double a = 0, double b = 0);      // resets x,y to a, b
};
请提供成员函数的定义和测试这个类的程序。

6.1头文件move10.h

#ifndef MOVE_H_
#define MOVE_H_
#include <iostream>
class Move
{
private:
	double x;
	double y;
public:
	Move(double a = 0, double b = 0);
	void showmove()const;
	Move& add(const Move& m)const;
	void reset(double a = 0, double b = 0);
};
#endif // !MOVE_H_

6.2成员函数.cpp

#include "move10.h"
#include <iostream>
using namespace std;
Move::Move(double a , double b)
{
	x = a;
	y = b;
}
void Move::showmove()const
{
	cout << "x = " << x << endl;
	cout << "y = " << y << endl;

}
Move& Move::add(const Move& m)const
{
	Move new_m;
	new_m.x = m.x + this->x;
	new_m.y = m.y + this->y;
	return new_m;

}
void Move::reset(double a , double b )
{
	x = a;
	y = b;
}

6.3使用类.cpp

#include "move10.h"
#include <iostream>
using namespace std;

int main(void)
{

	Move a;
	Move b = Move(120, 60);
	a.showmove();
	b.showmove();
	Move c = a.add(b);
	c.showmove();
	a = b.add(c);
	a.showmove();
	a.reset();
	a.showmove();

	system("pasue");
	return 0;
}

7. Betelgeusean plorg有这些特征。
数据:
    ·plorg的名称不超过19个字符
    ·plorg的满意指数(CI),这是一个整数
操作:
    ·新的plorg将有名称,其CI值为50
    ·plorg的CI可以修改
    ·plorg可以报告其名称和CI
请编写一个Plorg类声明(包括数据成员和成员函数原型)来表示plorg,并编写成员函数的函数定义。然后编写一个小程序,以演示Plorg类的所有特性。

7.1.头文件plorg10.h

#ifndef PLORG_H_
#include <iostream>

class Plorg
{
private:
	static const  int Len = 20;
	char m_name[Len];
	int m_CI;
public:
	Plorg();
	void SetName(const char* name);
	void SetCI(int CI);
	void showPlorg();

};
#endif // !PLORGA_H_

7.2.成员函数定义.cpp

#include "plorg10.h"
#include <iostream>
#include <string>
using namespace std;
Plorg::Plorg()
{
	strcpy_s(m_name,Len, "Plorga");
	m_CI = 0;
}
void Plorg::SetName(const char *name)
{
	strcpy_s(m_name,Len,  name);
	m_CI = 50;
}
void Plorg::SetCI(int CI)
{
	m_CI = CI;
}
void Plorg::showPlorg()
{
	cout << "The current information is as follows:" << endl;
	cout << "Name: " << m_name << endl;
	cout << "CI: " << m_CI << endl;
}

7.3.使用类.cpp

#include "plorg10.h"
#include <iostream>
#include <string>
using namespace std;
int main(void)
{
	Plorg p;
	p.showPlorg();
	p.SetName("LI Hua");
	p.showPlorg();
	p.SetCI(20);
	p.showPlorg();

	system("pause");
	return 0;
}

8. 可以将简单列表描述成下面这样
 ·可存储0或多个某种类型的列表
 ·可创建空列表
 ·可在列表中添加数据项
 ·可确定列表是否为空
 ·可确定列表是否为满
 ·可访问列表中的每一个数据项,并对它执行某种操作
 可以看到,这个列表确实很简单,例如,它不允许插入或删除数据项
 请设计一个List类来表示这种抽象类型。您应提供头文件list.h和实现文件list.cpp,前者包含类定义,后者包含类方法的实现。您还应该创建一个简短的程序来使用这个类
 该列表的规范很简单,这个主要旨在简化这个编程练习。可以选择使用数组或链表来实现该列表,但公有接口不应依赖于所做的选择。也就是说,公有接口不应有数组索引、节点指针等。
 应使用通用概念来表达创建列表、在列表中添加数据项等操作。对于访问数据项以及执行操作,通常应使用将函数指针作为参数的函数来处理:void visit(void (*pf)(Item &));
 其中。pf指向一个将Item引用作为参数的函数(而不是成员函数),Item是列表中数据项的类型。visit()函数将该函数用于列表中的每个数据项。

8.1头文件list.h

#ifndef LIST_H_
#define LIST_H_
#include <iostream>
#include <string>
using namespace std;

struct customer
{
	string name;
	double consumption;
};
typedef customer Item;
class List
{
private:
	static const int Len = 20;
	Item items[Len];
	int top = 0;
public:
	List();
	bool isempty() const;
	bool isfull() const;
	bool add(const Item& item);
	void visit(void(*pf)(Item& item));
	void showitem() const;

};
void turnover(Item& item);        //计算总营业额(列表中所有顾客消费额相加)
#endif // !LIST_H_

8.2list.cpp

#include "list10.h"
#include <iostream>
#include <string>
using namespace std;

double Sum = 0.0;
List::List()
{
	top = 0;
}
bool List::isempty() const
{
	return top == 0;
}
bool List::isfull() const
{
	return top == Len;
}
bool List::add(const Item& item)
{
    if (top < Len)
    {
        items[top++] = item;
        return true;
    }
    else
        return false;
}
void List::showitem() const
{
    for (int i = 0; i < top; i++)
    {
        cout << "#" << i + 1 <<":"<< endl;
        cout << "Name: " << items[i].name << endl;
        cout << "Consumption: " << items[i].consumption << endl;
    }
}
void List::visit(void(*pf)(Item& item))
{
    for (int i = 0; i < top; i++)
    {
        pf(items[i]);
    }
}

void turnover(Item& item)
{
    Sum += item.consumption;
}

8.3使用类.cpp
 

#include "list10.h"
#include <iostream>
using namespace std;
extern double Sum;
int main(void)
{
	List st;
	char ch;
	customer po;
	cout << "Please enter A to add a purchase order,V to caculate the turnover,S to show the items,or Q to quit." << endl;
	while (cin >> ch && toupper(ch) != 'Q')
	{
		while (cin.get() != '\n')
			continue;
		if (!isalpha(ch))
		{
			cout << "\a";
			continue;
		}
		switch (ch)
		{
		case'A':
		case 'a':
			cout << "Enter the name of customer:";
			getline(cin, po.name);
			cout << "Enter the payment: ";
			cin >> po.consumption;
			cin.get();
			if (st.isfull())
				cout << "List aleady full" << endl;
			else
				st.add(po);
			break;
		case 'S':
		case 's':
			st.showitem();
			break;
		case 'V':
		case 'v':
			if (st.isempty())
			{
				cout << "List is empty." << endl;
				cout << "Sum =  0"  << endl;
			}
			else
			{
				st.visit(turnover);
				cout <<"Sum = "<< Sum << endl;
			}
		}
		cout << "Please enter A to add a purchase order,V to caculate the turnover,S to show the items,or Q to quit." << endl;
	}
	cout << "Bye!" << endl;

	system("pause");
	return 0;
}

总结(注意事项):

  1. 文件间通用一个变量的方法是在一个文件中将其定义为全局变量后,其他文件使用关键字extern。
  2. 注意使用函数指针做参数的用法。

第11章 使用类

1.修改程序清单11.5,使之将一系列连续的随机漫步者位置写入到文件中。对于每个位置,用步号进行标志。另外,让该程序将初始条件(目标距离和步长)以及结果小结写入到该文件中。该文件的内容与下面类似:
Target Distance: 100, Step Size: 20
0: (x,y) = (0, 0)
1: (x,y) = (-11.4715, 16.383)
2: (x,y) = (-868807, -3.42232)
....
26: (x,y) = (42.2919, -78.2594)
27: (x,y) = (58.6749, -89.7309)
After 27 steps, the subject has the following location:
(x,y) = (58.6749, -89.7309)
or
(m,a) = (107.212, -56.8194)Average outward distance per step = 3.97081

答:与源程序相比,头文件以及成员函数定义无需改动,仅在主函数程序文件做改动,如下所示。

1.1.头文件vector11.h

#ifndef VECTOR_H_
#define VECTOR_H_
#include <iostream>
namespace VECTOR
{
	class Vector
	{
	public:
		enum Mode{RECT,POL};
	private:
		double x;
		double y;
		double mag;
		double ang;
		Mode mode;

		void set_mag();
		void set_ang();
		void set_x();
		void set_y();
	public:
		Vector();
		Vector(double n1, double n2, Mode from = RECT);
		void reset(double n1, double n2, Mode from = RECT);
		~Vector();
		double xval()const { return x; };
		double yval()const { return y; };
		double magval() const { return mag; };
		double angval()const { return ang; };
		void polar_mode();
		void rect_mode();

		Vector operator+(const Vector& b)const;
		Vector operator-(const Vector& b)const;
		Vector operator-()const;
		Vector operator*(double n)const;

		friend Vector operator*(double n, const Vector& a);
		friend std::ostream& operator<<(std::ostream& os, const Vector& v);
	};

}
#endif // !VECTOR_H_

1.2成员函数定义.cpp

#include "vector11.h"
#include <iostream>
#include <cmath>
using namespace  std;
namespace VECTOR
{
	const double Rad_to_deg = 45.0 / atan(1.0);
	void Vector::set_mag()
	{
		mag = sqrt(x * x + y * y);
	}
	void Vector::set_ang()
	{
		if (x == 0 && y == 0)
		{
			ang = 0.0;
		}
		else
			ang = atan2(y, x);
	}
	void Vector::set_x()
	{
		x = mag * cos(ang);
	}
	void Vector::set_y()
	{
		y = mag * sin(ang);
	}
	Vector::Vector()
	{
		x = y = mag = ang = 0.0;
		mode = RECT;
	}
	Vector::Vector(double n1, double n2, Mode from)
	{
		mode = from;
		if (from == RECT)
		{
			x = n1;
			y = n2;
			set_ang();
			set_mag();
		}
		else if(from == POL)
		{
			mag = n1;
			ang = n2 / Rad_to_deg;
			set_x();
			set_y();
		}
		else
		{
			cout << "Incorrect 3rd argument to Vector()--";
			cout << "vector set to 0" << endl;
			x = y = mag = ang = 0.0;
			mode = RECT;
		}
	}
	void Vector::reset(double n1, double n2, Mode from)
	{
		mode = from;
		if (from == RECT)
		{
			x = n1;
			y = n2;
			set_mag();
			set_ang();
		}
		else if (from == POL)
		{
			mag = n1;
			ang = n2 / Rad_to_deg;
			set_x();
			set_y();
		}
		else
		{
			cout << "Incorrect 3rd argument to Vector()--";
			cout << "vector set to 0" << endl;
			x = y = mag = ang = 0.0;
			mode = RECT;
		}
	}
	Vector::~Vector()
	{

	}
	
	void Vector::polar_mode()
	{
		mode = POL;
	}
	void Vector::rect_mode()
	{
		mode = RECT;
	}
	Vector Vector::operator+(const Vector& b)const
	{
		return Vector(x + b.x, y + b.y);
	}
	Vector Vector::operator-(const Vector& b)const
	{
		return Vector(x - b.x, y - b.y);
	}
	Vector Vector::operator-()const
	{
		return Vector(-x, -y);
	}
	Vector Vector::operator*(double n)const
	{
		return Vector(n * x, n * y);
	}
	Vector operator*(double n, const Vector& a)
	{
		return a * n;
	}
	ostream& operator<<(ostream& os, const Vector& v)
	{
		if (v.mode == Vector::RECT)
			os << "(x,y) = (" << v.x << "," << v.y << ")";
		else if (v.mode == Vector::POL)
			os << "(m,a) = (" << v.mag << "," << v.ang << ")";
		else
			os << "Vector object mode is invalid";
		return os;
   }

}

1.3使用类.cpp

#include <iostream>
#include <cstdlib>     //rand()、srand()
#include <ctime>        //time()
#include "vector11.h"
#include <fstream>
using namespace std;
int main()
{
	using VECTOR::Vector;
	ofstream outFile;
	outFile.open("11.1randwalker.txt");
	
	srand(time(0));
	double direction;
	Vector step;
	Vector result(0.0, 0.0);
	unsigned long steps = 0;
	double target;
	double dstep;
	cout << "Enter target distance:(q to quit)";
	while (cin >> target)
	{
		cout << "Enter step length:";
		if (!(cin >> dstep))
			break;
		outFile<< "Target Distance: " << target << ", " << "Step Size: " << dstep << endl;
		while (result.magval() < target)
		{
			outFile << steps << ": " << result << endl;
			direction = rand() % 360;
			step.reset(dstep, direction, Vector::POL);
			result = result + step;
			steps++;
		}
		cout << "After " << steps << " steps,the subject ""has the following location:" << endl;
		outFile << "After " << steps << " steps,the subject ""has the following location:" << endl;
		cout << result << endl;
	    outFile << result << endl;
		result.polar_mode();
		cout << " or\n" << result << endl;
		cout << "Average outward distance per step = " << result.magval() / steps << endl;
		outFile << " or\n" << result << endl;
		outFile << "Average outward distance per step = " << result.magval() / steps << endl;
		steps = 0;
		result.reset(0.0, 0.0);
		cout << "Enter target distance(q to quit):";
	}
	cout << "Bye!" << endl;
	cin.clear();
	while (cin.get() != '\n')
		continue;

	outFile.close();
	system("pause");
	return 0;

}

结果展示:


2.对于Vector类的头文件(程序清单11.13)和实现文件(程序清单11.14)进行修改,使其不再储存矢量的长度和角度,而是在magval()和angval()被调用时计算它们。
应保留公有接口不变(公有方法及其参数不变),但对私有部分(包括一些私有方法)和方法实现进行修改。然后,使用程序清单11.15对修改后的版本进行测试,结果应该与以前相同,因为Vecotr类的公有接口与原来相同。

2.1头文件vector112.h有修改,删除了两个私有变量,修改了两个私有成员函数。

#ifndef VECTOR112_H_
#define VECTOR112_H_
#include <iostream>
namespace VECTOR
{
	class Vector
	{
	public:
		enum Mode { RECT, POL };
	private:
		double x;
		double y;
		Mode mode;

		double set_mag();
		double set_ang();
		void set_x(double mag, double ang);
		void set_y(double mag, double ang);
	public:
		Vector();
		Vector(double n1, double n2, Mode from = RECT);
		void reset(double n1, double n2, Mode from = RECT);
		~Vector();
		double xval()const { return x; };
		double yval()const { return y; };
		double magval() const;
		double angval()const;
		void polar_mode();
		void rect_mode();

		Vector operator+(const Vector& b)const;
		Vector operator-(const Vector& b)const;
		Vector operator-()const;
		Vector operator*(double n)const;

		friend Vector operator*(double n, const Vector& a);
		friend std::ostream& operator<<(std::ostream& os, const Vector& v);
	};

}
#endif // !VECTOR_H_

2.2成员函数定义.cpp (有修改)

#include "vector112.h"
#include <iostream>
#include <cmath>
using namespace std;
namespace VECTOR
{
	const double Rad_to_deg = 45.0 / atan(1.0);
	double Vector::set_mag()
	{
		double mag;
		mag = sqrt(x * x + y * y);
		return mag;
	}
	double Vector::set_ang()
	{
		double ang;
		if (x == 0 && y == 0)
		{
			ang = 0.0;
		}
		else
			ang = atan2(y, x);
		return ang;
	}
	void Vector::set_x(double mag,double ang)
	{
		x = mag * cos(ang);
	}
	void Vector::set_y(double mag,double ang)
	{
		y = mag * sin(ang);
	}
	Vector::Vector()
	{
		x = y = 0;
		mode = RECT;
	}
	Vector::Vector(double n1, double n2, Mode from)
	{
		mode = from;
		if (from == RECT)
		{
			x = n1;
			y = n2;
			set_mag();
			set_ang();
		}
		else if(from == POL)
		{
			double mag, ang;
			mag = n1;
			ang = n2 / Rad_to_deg;
			set_x(mag,ang);
			set_y(mag,ang);
		}
		else
		{
			cout << "Incorrect 3rd argument to Vector()--";
			cout << "vector set to 0" << endl;
			x = y = 0.0;
			mode = RECT;
		}
	}
	void Vector::reset(double n1, double n2, Mode from)
	{
		mode = from;
		if (from == RECT)
		{
			x = n1;
			y = n2;
		}
		else if (from == POL)
		{
			double mag, ang;
			mag = n1;
			ang = n2 / Rad_to_deg;
			set_x(mag,ang);
			set_y(mag,ang);
		}
		else
		{
			cout << "Incorrect 3rd argument to Vector()--";
			cout << "vector set to 0" << endl;
			x = y = 0.0;
			mode = RECT;
		}
	}
	Vector::~Vector()
	{

	}
	double Vector::magval() const
	{
		double mag;
		mag = sqrt(x * x + y * y);
		return mag;
	}

	double Vector::angval() const
	{
		double ang;
		if (x == 0.0 && y == 0.0)
			ang = 0.0;
		else
			ang = atan2(y, x);
		return ang;
	}
	
	void Vector::polar_mode()
	{
		mode = POL;
	}
	void Vector::rect_mode()
	{
		mode = RECT;
	}
	Vector Vector::operator+(const Vector& b)const
	{
		return Vector(x + b.x, y + b.y);
	}
	Vector Vector::operator-(const Vector& b)const
	{
		return Vector(x - b.x, y - b.y);
	}
	Vector Vector::operator-()const
	{
		return Vector(-x, -y);
	}
	Vector Vector::operator*(double n)const
	{
		return Vector(n * x, n * y);
	}
	Vector operator*(double n, const Vector& a)
	{
		return a * n;
	}
	ostream& operator<<(ostream& os, const Vector& v)
	{
		if (v.mode == Vector::RECT)
			os << "(x,y) = (" << v.x << "," << v.y << ")";
		else if (v.mode == Vector::POL)

			os << "(m,a) = (" << v.magval()<< "," << v.angval() << ")";
		else
			os << "Vector object mode is invalid";
		return os;
	 }
}

2.3使用类main函数(无修改)

#include <iostream>
#include <cstdlib>     //rand()、srand()
#include <ctime>        //time()
#include "vector112.h"
using namespace std;
int main()
{
	using VECTOR::Vector;
	srand(time(0));
	double direction;
	Vector step;
	Vector result(0.0, 0.0);
	unsigned long steps = 0;
	double target;
	double dstep;
	cout << "Enter target distance:(q to quit)";
	while (cin >> target)
	{
		cout << "Enter step length:";
		if (!(cin >> dstep))
			break;
		while (result.magval() < target)
		{
			direction = rand() % 360;
			step.reset(dstep, direction, Vector::POL);
			result = result + step;
			steps++;
		}
		cout << "After " << steps << " steps,the subject ""has the following location:" << endl;
		cout << result << endl;
		result.polar_mode();
		cout << " or\n" << result << endl;
		cout << "Average outward distance per step = " << result.magval() / steps << endl;
		steps = 0;
		result.reset(0.0, 0.0);
		cout << "Enter target distance(q to quit):";
	}
	cout << "Bye!" << endl;
	cin.clear();
	while (cin.get() != '\n')
		continue;

	system("pause");
	return 0;

}

3. 修改程序清单11.15,使之报告N次测试中的最高、最低和平均步数(其中N是用户输入的整数),而不是报告每次测试的结果。

3.1头文件vector113.h同上题

#ifndef VECTOR112_H_
#define VECTOR112_H_
#include <iostream>
namespace VECTOR
{
	class Vector
	{
	public:
		enum Mode { RECT, POL };
	private:
		double x;
		double y;
		Mode mode;

		double set_mag();
		double set_ang();
		void set_x(double mag, double ang);
		void set_y(double mag, double ang);
	public:
		Vector();
		Vector(double n1, double n2, Mode from = RECT);
		void reset(double n1, double n2, Mode from = RECT);
		~Vector();
		double xval()const { return x; };
		double yval()const { return y; };
		double magval() const;
		double angval()const;
		void polar_mode();
		void rect_mode();

		Vector operator+(const Vector& b)const;
		Vector operator-(const Vector& b)const;
		Vector operator-()const;
		Vector operator*(double n)const;

		friend Vector operator*(double n, const Vector& a);
		friend std::ostream& operator<<(std::ostream& os, const Vector& v);
	};

}
#endif // !VECTOR_H_

3.2成员函数定义.cpp同上题

#include "vector113.h"
#include <iostream>
#include <cmath>
using namespace std;
namespace VECTOR
{
	const double Rad_to_deg = 45.0 / atan(1.0);
	double Vector::set_mag()
	{
		double mag;
		mag = sqrt(x * x + y * y);
		return mag;
	}
	double Vector::set_ang()
	{
		double ang;
		if (x == 0 && y == 0)
		{
			ang = 0.0;
		}
		else
			ang = atan2(y, x);
		return ang;
	}
	void Vector::set_x(double mag,double ang)
	{
		x = mag * cos(ang);
	}
	void Vector::set_y(double mag,double ang)
	{
		y = mag * sin(ang);
	}
	Vector::Vector()
	{
		x = y = 0;
		mode = RECT;
	}
	Vector::Vector(double n1, double n2, Mode from)
	{
		mode = from;
		if (from == RECT)
		{
			x = n1;
			y = n2;
			set_mag();
			set_ang();
		}
		else if(from == POL)
		{
			double mag, ang;
			mag = n1;
			ang = n2 / Rad_to_deg;
			set_x(mag,ang);
			set_y(mag,ang);
		}
		else
		{
			cout << "Incorrect 3rd argument to Vector()--";
			cout << "vector set to 0" << endl;
			x = y = 0.0;
			mode = RECT;
		}
	}
	void Vector::reset(double n1, double n2, Mode from)
	{
		mode = from;
		if (from == RECT)
		{
			x = n1;
			y = n2;
		}
		else if (from == POL)
		{
			double mag, ang;
			mag = n1;
			ang = n2 / Rad_to_deg;
			set_x(mag,ang);
			set_y(mag,ang);
		}
		else
		{
			cout << "Incorrect 3rd argument to Vector()--";
			cout << "vector set to 0" << endl;
			x = y = 0.0;
			mode = RECT;
		}
	}
	Vector::~Vector()
	{

	}
	double Vector::magval() const
	{
		double mag;
		mag = sqrt(x * x + y * y);
		return mag;
	}

	double Vector::angval() const
	{
		double ang;
		if (x == 0.0 && y == 0.0)
			ang = 0.0;
		else
			ang = atan2(y, x);
		return ang;
	}
	
	void Vector::polar_mode()
	{
		mode = POL;
	}
	void Vector::rect_mode()
	{
		mode = RECT;
	}
	Vector Vector::operator+(const Vector& b)const
	{
		return Vector(x + b.x, y + b.y);
	}
	Vector Vector::operator-(const Vector& b)const
	{
		return Vector(x - b.x, y - b.y);
	}
	Vector Vector::operator-()const
	{
		return Vector(-x, -y);
	}
	Vector Vector::operator*(double n)const
	{
		return Vector(n * x, n * y);
	}
	Vector operator*(double n, const Vector& a)
	{
		return a * n;
	}
	ostream& operator<<(ostream& os, const Vector& v)
	{
		if (v.mode == Vector::RECT)
			os << "(x,y) = (" << v.x << "," << v.y << ")";
		else if (v.mode == Vector::POL)

			os << "(m,a) = (" << v.magval()<< "," << v.angval() << ")";
		else
			os << "Vector object mode is invalid";
		return os;
	 }
}

3.3使用类.cpp做修改

#include <iostream>
#include <cstdlib>     //rand()、srand()
#include <ctime>        //time()
#include "vector113.h"
using namespace std;
int main()
{
	using VECTOR::Vector;
	srand(time(0));
	double direction;
	Vector step;
	Vector result(0.0, 0.0);
	unsigned long steps = 0;
	double target;
	double dstep;

	int max = 0;
	int min = 100000;
	int sum = 0;
	double average = 0.0;
	int N;
	cout << "Test times:";
	cin >> N;
		
	for (int i = 0; i < N; i++)
	{
		cout << "Enter target distance:(q to quit)";
		cin >> target;
		cout << "Enter step length:";
		cin >> dstep;
		while (result.magval() < target)
		{
			direction = rand() % 360;
			step.reset(dstep, direction, Vector::POL);
			result = result + step;
			steps++;
		}
		cout << "# "<<i+1<<":"<<"After " << steps << " the subject reach destination." << endl;
		max = max > steps ? max : steps;
		min = min < steps ? min : steps;
		sum += steps;
		steps = 0;
		result.reset(0.0, 0.0);
	}

	average = double(sum) / N;
	cout << "The max steps is: " << max << endl;
	cout << "The min steps is: " << min << endl;
	cout << "The average steps is: " << average << endl;
	cout << "Bye!" << endl;
	cin.clear();
	
	system("pause");
	return 0;

}

4.重新编写最后的Time类示例(程序清单11.10、程序清单11.11和程序清单11.12),使用友元函数来实现所有的重载运算符。

4.1头文件mytime114.h

#ifndef MYTIME114_H_
#define MYTIME114_H_
#include <iostream>
class Time
{
private:
	int hours;
	int minutes;
public:
	Time();
	Time(int h, int m = 0);
	void AddMin(int m);
	void AddHr(int h);
	void Reset(int h = 0, int m = 0);
	

	friend Time operator+(const Time& t1,const Time &t2);
	friend Time operator-(const Time& t1,const Time &t2);
	friend Time operator*(const Time & t,double mult);
	friend Time operator* (double m, const Time& t) { return t * m; }
	friend std::ostream& operator<< (std::ostream & os, const Time & t);
};
#endif 


4.2成员函数定义.cpp

#include "mytime114.h"
#include <iostream>

Time::Time()
{
	hours = minutes = 0;
}
Time::Time(int h, int m)
{
	hours = h;
	minutes = m;
}
void Time::AddMin(int m)
{
	hours += m;
	hours += minutes / 10;
	minutes %= 60;
}
void Time::AddHr(int h)
{
	hours += h;
}
void Time::Reset(int h, int m)
{
	hours = h;
	minutes = m;
}


 Time operator+(const Time& t1, const Time& t2)
{
	 Time sum;
	 sum.minutes =t1.minutes + t2.minutes;
	 sum.hours = t1.hours + t2.hours + sum.minutes / 60;
	 sum.minutes %= 60;
	 return sum;
}
 Time operator-(const Time& t1, const Time& t2)
 {
	 Time diff;
	 int tot1, tot2;	
	 tot1 = t1.minutes + 60 * t1.hours;
	 tot2 = t2.minutes + 60 *t2. hours;
	 diff.hours = (tot2 - tot1) / 60;
	 diff.minutes = (tot2 - tot1) % 60;
	 return diff;
 }
 Time operator*(const Time& t, double mult)
 {
	 Time result;
	 long totalminutes = t.hours * mult * 60 + t.minutes * mult;
	 result.hours = totalminutes / 60;
	 result.minutes = totalminutes % 60;
	 return result;
}
std::ostream& operator<< (std::ostream& os, const Time& t)
{
	os << t.hours << "hours, " << t.minutes << " minutes";
	return os;
}

4.3使用类.cpp(不改变,与程序清单11.12相同)

#include "mytime114.h"
#include <iostream>

int main(void)
{
	using std::cout;
	using std::endl;
	Time aida(3, 25);
	Time tosca(2, 48);
	Time temp;

	cout << "Aida and Tosca:" << endl;
	cout << aida << " ; " << tosca << endl;
	temp = aida + tosca;
	cout << "Aida + Tosca: " << temp << endl;
	temp = aida * 1.17;
	cout << "Aida * 1.17: " << temp << endl;
	cout << "10.0*Tosca: " << 10.0 * tosca << endl;

	system("pause");
	return 0;
}

5.重新编写Stonewt类(程序清单11.16和程序清单11.17),使它有一个状态成员,由该状态成员控制对象应转换为英石格式、整数磅格式还是浮点磅格式。重载<<运算符,使用它来替换show_stn()和show_lbs()方法。重载加法、减法和乘发运算符,以便可以对Stonewt值进行加、减、乘运算。编写一个使用所有类方法和友元的小程序,来测试这个类。

5.1头文件stonewt115.h

#ifndef STONEWT115_H_
#define STONEWT115_H_
#include <iostream>
class Stonewt
{
public:
	enum Format { st, intp, doublep };
private:
	enum { Lbs_per_stn = 14 };
	int stone;
	double pds_left;
	double pounds;
	Format m_form;
public:
	Stonewt(double lbs);
	Stonewt(int stn, double lbs);
	Stonewt();
	~Stonewt();
	void SetFormat(Format form);
	Stonewt operator+ (const Stonewt& s)const;
	Stonewt operator- (const Stonewt& s)const;
	Stonewt operator* (double n)const;
	friend Stonewt operator*(double m, const Stonewt& s){return s * m;}   
	friend std::ostream& operator<< (std::ostream& os, const Stonewt& s);
};
#endif 

5.2成员函数定义.cpp

#include "stonewt115.h"
#include <iostream>

Stonewt::Stonewt(double lbs)
{
	stone = int(lbs) / Lbs_per_stn;
	pds_left = int(lbs) % Lbs_per_stn + lbs - int(lbs);
	pounds = lbs;
	m_form = st;
}
Stonewt::Stonewt(int stn, double lbs)
{
	stone = stn;
	pds_left = lbs;
	pounds = stn * Lbs_per_stn + lbs;
	m_form = intp;
}
Stonewt::Stonewt()
{
	stone = pounds = pds_left = 0;
	m_form = doublep;
}
Stonewt::~Stonewt()
{

}
void Stonewt::SetFormat(Format from)
{
	m_form = from;
}
Stonewt Stonewt::operator+ (const Stonewt& s)const
{
	Stonewt sum;
	sum.pounds = pounds + s.pounds;
	sum.stone = int(sum.pounds) / Lbs_per_stn;
	sum.pds_left = int(sum.pounds) % Lbs_per_stn + sum.pounds - int(sum.pounds);
	return sum;
}
Stonewt Stonewt::operator- (const Stonewt& s)const
{
	Stonewt diff;
	diff.pounds = pounds - s.pounds;
	diff.stone = int(diff.pounds) / Lbs_per_stn;
	diff.pds_left = int(diff.pounds) % Lbs_per_stn + diff.pounds - int(diff.pounds);
	return diff;
}
Stonewt Stonewt::operator* (double n)const
{
	double mult;
	mult = pounds * n;
	return Stonewt(mult);
}
std::ostream& operator<< (std::ostream& os, const Stonewt& s)
{
	if (s.m_form == Stonewt::st)
	{
		os << s.stone << " stone, " << s.pds_left << " pounds\n";
	}
	else if (s.m_form == Stonewt::intp)
	{
		os << int(s.pounds) << " pounds\n";
	}
	else if (s.m_form == Stonewt::doublep)
	{
		os << s.pounds << " pounds\n";
	}
	else
		os << "Stonewt state is invalid";
	return os;
}

5.3使用类.cpp

#include "stonewt115.h"
#include <iostream>
using std::cout;
using std::cin;
int main(void)
{

	Stonewt incognito = 275;
	Stonewt wolfe(285.7);
	Stonewt taft(21, 8);

	cout << "The celebrity weighed: " << incognito ;   //st
	cout << "The detective weighed: " << wolfe;         //st
	cout << "The President weighed: " << taft << "\n";            //intp

	Stonewt tf(2);
	Stonewt sum, diff, mult;
	sum = incognito + tf;
	diff = wolfe - tf;
	mult = taft * 2;
	cout << "The result will display as double_pounds: \n";
	cout << "After dinner, the celebrity weighed: ";
	sum.SetFormat(Stonewt::doublep);
	cout << sum;
	cout << "After sport, the detective weighed: ";
	diff.SetFormat(Stonewt::doublep);
	cout << diff;
	cout << "Now,the President weighed: ";
	mult.SetFormat(Stonewt::doublep);
	cout << mult;

	system("pause");
	return 0;
}

6.重新编写Stonewt类(程序清单11.16和程序清单11.17),重载全部6个关系运算符。运算符对pounds成员进行比较,并返回一个bool值。编写一个程序,它声明一个包含6个Stonewt对象的数组,并在数组声明中初始化前3个对象。然后使用循环来读取用于设置剩余3个数组元素的值。接着报告最小的元素、最大的元素以及大于或等于11英石的元素的数量(最简单的方法是创建一个Stonewt对象,并将其初始化为11英石,然后将其同其他对象进行比较)。

6.1头文件stonewt116.ch

#ifndef STONEWT116_H_
#define STONEWT116_H_
#include <iostream>
class Stonewt
{
public:
	enum Format { st, intp, doublep };
private:
	enum { Lbs_per_stn = 14 };
	int stone;
	double pds_left;
	double pounds;
	Format state;
public:
	Stonewt(double lbs);
	Stonewt(int stn, double lbs);
	Stonewt();
	~Stonewt();
	
	void Setstate(Format x);
	friend bool operator>(const Stonewt& s1, const Stonewt& s2);
	friend bool operator<(const Stonewt& s1, const Stonewt& s2);
	friend bool operator>=(const Stonewt& s1, const Stonewt& s2);
	friend bool operator<=(const Stonewt& s1, const Stonewt& s2);
	friend bool operator==(const Stonewt& s1, const Stonewt& s2);
	friend bool operator!=(const Stonewt& s1, const Stonewt& s2);
	friend std::ostream& operator<< (std::ostream& os, const Stonewt& s);

};
#endif 

6.2成员函数定义.cpp

#include "stonewt116.h"
#include <iostream>
using std::cout;
using std::endl;
using namespace std;
Stonewt::Stonewt(double lbs)
{
	stone = int(lbs) / Lbs_per_stn;
	pds_left = int(lbs) % Lbs_per_stn + lbs - int(lbs);
	pounds = lbs;
	state = st;
}
Stonewt::Stonewt(int stn, double lbs)
{
	stone = stn;
	pds_left = lbs;
	pounds = stn * Lbs_per_stn + lbs;
	state = st;
}
Stonewt::Stonewt()
{
	stone = pounds = pds_left = 0;
	state = st;
}
Stonewt::~Stonewt()
{

}

void Stonewt::Setstate(Format x)
{
	state = x;
}
bool operator>(const Stonewt& s1, const Stonewt& s2)
{
	if (s1.pounds > s2.pounds)
		return true;
	else
		return false;
}
bool operator<(const Stonewt& s1, const Stonewt& s2)
{
	if (s1.pounds < s2.pounds)
		return true;
	else
		return false;
}
bool operator>=(const Stonewt& s1, const Stonewt& s2)
{
	if (s1.pounds >= s2.pounds)
		return true;
	else
		return false;
}
bool operator<=(const Stonewt& s1, const Stonewt& s2)
{
	if (s1.pounds <= s2.pounds)
		return true;
	else
		return false;
}
bool operator==(const Stonewt& s1, const Stonewt& s2)
{
	if (s1.pounds == s2.pounds)
		return true;
	else
		return false;
}
bool operator!=(const Stonewt& s1, const Stonewt& s2)
{
	if (s1.pounds != s2.pounds)
		return true;
	else
		return false;
}
ostream& operator<< (ostream& os, const Stonewt& s)
{
	if (s.state == Stonewt::st)
	{
		os << s.stone << " stone, " << s.pds_left << " pounds\n";
	}
	else if (s.state == Stonewt::intp)
	{
		os << int(s.pounds) << " pounds\n";
	}
	else if (s.state == Stonewt::doublep)
	{
		os << s.pounds << " pounds\n";
	}
	else
		os << "Stonewt state is invalid";
	return os;
}

6.3主函数.cpp

#include <iostream>
using namespace std;
#include "stonewt116.h"
//编写一个程序,它声明一个包含6个Stonewt对象的数组,
//并在数组声明中初始化前3个对象。
//然后使用循环来读取用于设置剩余3个数组元素的值。
//接着报告最小的元素、最大的元素以及大于或等于11英石的元素的数量
//最简单的方法是创建一个Stonewt对象,并将其初始化为11英石,然后将其同其他对象进行比较
int main(void)
{
	Stonewt s[6] = {{200.0},{100.2},{21,5.2} };
	cout << "Enter the rest three Stonewt:\n";
	for (int i = 3; i < 6; i++)
	{
		double pounds;
		cout << "#" << i + 1 << ": ";
		cin >> pounds;
		s[i] = pounds;
	}

	Stonewt max = s[0];
	Stonewt min = s[0];
	const Stonewt flag(11, 0);
	int count = 0;
	for (int i = 0; i < 6; i++)
	{
		max = max > s[i] ? max : s[i];
		min = min < s[i] ? min : s[i];
		if (s[i] >= flag)
			count++;
	}

	cout << "The max is: " << max;
	cout << "The min is: " << min;
	cout << "There are " << count << " memeber bigger than 11 stone.\n";

	system("pause");
	return 0;
}

7.复数有两个部分组成:实数部分和虚数部分。复数的一种书写方式是:(3.0,4.0),其中,3.0是实数部分,4.0是虚数部分。假设a=(A,Bi),c=(C,Di),则下面是一些复数运算。
加法:a+c=(A+C,(B+D)i)。
减法:a-c=(A-C,(B-D)i)。
乘法:a * c=(A*C-B * D,(A * D+B * C)i)。
乘法:x * c=(x * C,x * Di),其中x为实数。
共轭:~a=(A,-Bi)。
请定义一个复数类,以便下面的程序可以使用它来获得正确的结果。
(……代码省略……)
注意。必须重载运算符<<和>>。标准C++使用头文件complex提供了比这个示例更广泛的复数支持,因此应将自定义的头文件命名为complex0.h,以免发生冲突。应尽可能使用const。
下面是该程序的运行情况。
(……代码省略……)
请注意,经过重载后,cin>>c将提示用户输入实数和虚数部分。

7.1头文件complex117.h

#ifndef COMPLEX117_H_
#define COMPLEX117_H_
#include <iostream>
class Complex
{
private:
	double real;
	double imag;
public:
	Complex();
	Complex(double m, double n);
	~Complex();
	Complex operator+(const Complex& c)const;
	Complex operator-(const Complex& c)const;
	Complex operator*(const Complex& c)const;
	Complex operator*(double x)const;
	friend Complex operator*(double n, const Complex& m){return m * n;}
	Complex operator~()const;
	friend std::ostream& operator<<(std::ostream& os, const Complex& n);
	friend std::istream& operator>>(std::istream& is, Complex& n);
};

#endif // !COMPLEX117_H_

7.2成员函数定义.cpp

#include "complex117.h"
#include <iostream>
using namespace std;
Complex::Complex()
{
	real = imag = 0.0;
}
Complex::Complex(double m, double n)
{
	real = m;
	imag = n;
}
Complex::~Complex()
{

}
Complex Complex::operator+(const Complex& c)const
{
	Complex sum;
	sum.real = c.real + this->real;
	sum.imag = c.imag + this->imag;
	return sum;
}
Complex Complex::operator-(const Complex& c)const
{
	Complex diff;
	diff.real =  this->real - c.real;
	diff.imag =  this->imag - c.imag;
	return diff;
}
Complex Complex::operator*(const Complex& c)const
{
	Complex mult1;
	mult1.real = this->real * c.real - this->imag * c.imag;
	mult1.imag = this->real * c.imag + this->imag * c.real;
	return mult1;
}
Complex Complex::operator*(double x)const
{
	Complex mult2;
	mult2.real = this->real * x;
	mult2.imag = this->imag * x;
	return mult2;
}
Complex Complex::operator~()const
{
	Complex temp;
	temp.real =this-> real;
	temp.imag = -(this->imag);
	return temp;
}
std::ostream& operator<<(std::ostream& os, const Complex& x)
{
	os << "(" << x.real << ", " << x.imag << "i)";
	return os;
}
std::istream& operator>>(std::istream& is, Complex& x)
{
	cout << "real: ";
	is >> x.real;
	if(x.real )
	{
		cout << "imaginary: ";
		is >> x.imag;
	}
	return is;
}

7.3使用类.cpp

#include <iostream>
#include "complex117.h"
using namespace std;

int main(void)
{
	Complex a(3.0, 4.0);
	Complex c;

	cout << "Enter a complex number(q to quit):\n";
	while (cin >> c)
	{
		cout << "c is " << c << endl;
		cout << "complex conjugate is " << ~c << endl;
		cout << "a is " << a << endl;
		cout << "a + c is " << a + c << endl;
		cout << "a - c is " << a - c << endl;
		cout << "a * c is " << a * c << endl;
		cout << "2 * c is " << 2 * c << endl;
		cout << "Enter a complex number (q to quit):" << endl;
	}
	cout << "Done!" << endl;
	system("pause");
	return 0;
}

第12章 类和动态内存分配

1.对于下面的类声明:

(……代码忽略……)

给这个类提供实现,并编写一个使用所有成员函数的小程序。

笔记:#pragma warning(disable:4996)      //解决strcpy报错的问题

1.1头文件cow121.h

#ifndef  COW121_H_
#define COW121_H_
#pragma warning(disable:4996)      //解决strcpy报错的问题
class Cow
{
private:
	char name[20];
	char* hobby;
	double weight;
public:
	Cow();
	Cow(const char* nm, const char* ho, double wt);
	Cow(const Cow &c);
	~Cow();
	Cow& operator= (const Cow& c);
	void ShowCow()const;
};
#endif // ! Cow121_H_

 1.2成员函数定义.cpp

#include <iostream>
#include <cstring>
#include "cow121.h"
using std::endl;
using std::cout;
Cow::Cow()
{
	name[0] = '\0';
	hobby = new char[1];
	hobby[0] = '\0';
	weight = 0.0;
}
Cow::Cow(const char* nm, const char* ho, double wt)
{
	strcpy(name, nm);
	hobby = new char[strlen(ho) + 1];
	strcpy(hobby, ho);
	weight = wt;
}
Cow::Cow(const Cow& c)
{
	strcpy(name, c.name);
	hobby = new char[strlen(c.hobby) + 1];
	strcpy(hobby,c.hobby);
	weight = c.weight;
}
Cow::~Cow()
{
	delete[] hobby;
}
Cow& Cow::operator= (const Cow& c)
{
	delete[] hobby;
	strcpy(name,c.name);
	hobby = new char[strlen(c.hobby) + 1];
	strcpy(hobby, c.hobby);
	weight = c.weight;
	return *this;
}

void Cow::ShowCow()const
{
	cout << "Name: " << name << endl;
	cout << "Hobby: " << hobby << endl;
	cout << "Weight: " << weight << endl;
	cout << endl;
}

1.3使用类.cpp

#include "cow121.h"
#include <iostream>
using std::cout;
using std::endl;
int main(void)
{
	Cow c1;
	cout << "c1:" << endl;
	c1.ShowCow();
	Cow c2("Yonggan Niuniu", "study", 100.23);
	cout << "c2:" << endl;
	c2.ShowCow();
	Cow c3("Tangping Niuniu", "play game", 150.80);
	cout << "c3:" << endl;
	c3.ShowCow();
	Cow c4(c2);
	cout << "c4:" << endl;
	c4.ShowCow();
	c1 = c3;
	cout << "c1 = c3:" << endl;
	c3.ShowCow();
	c1.ShowCow();

	system("pause");
	return 0;
}

2.通过完成下面的工作来改进String类声明(即将String1.h升级为String2.h)。

a. 对+运算符进行重载,使之可将两个字符串合并成1个。

b. 提供一个Stringlow()成员函数,将字符串中所有的字母字符转换为小写(别忘了cctype系列字符函数)。

c. 提供String()成员函数,将字符串中所有字母字符转换成大写。

d. 提供一个这样的成员函数,它接受一个char参数,返回该字符在字符串中出现的次数。

使用下面的程序来测试您的工作:

(……代码忽略……)

输出应与下面相似:

(……代码忽略……)

笔记:strcpy(temp+len, s.str);  //注意!!!   是temp+len而不是temp,意味着从temp[len]开始复制。

2.1头文件string122.h

#ifndef STRING122_H_
#define STRING122_H_
#pragma warning(disable:4996)   
#include <iostream>
using std::ostream;
using std::istream;

class String
{
private:
	char* str;
	int len;
	static int num_strings;
	static const int CINLIM = 80;

public:
	String(const char* s);
	String();
	String(const String& st);
	~String();
	int length()const { return len; }

	//重载
	String& operator=(const String& st);
	String& operator=(const char* s);
	char& operator[](int i);
	const char& operator[](int i)const;

	//友元
	friend bool operator<(const String& st1, const String& st2);
	friend bool operator>(const String& st1, const String& st2);
	friend bool operator==(const String& st1, const String& st2);
	friend ostream& operator<<(ostream& os, const String& st);
	friend istream& operator>>(istream& is, String& st);
	//static function
	static int Howmany();

	//新增函数
	//a.对 + 运算符进行重载,使之可将两个字符串合并成1个。
	String operator+(const String &s)const;
	String operator+(const char* s)const;
	friend String operator+(const char* s1, const String& s2);
	//b.提供一个Stringlow()成员函数,将字符串中所有的字母字符转换为小写。
	void stringlow();
	//c.提供String()成员函数,将字符串中所有字母字符转换成大写。
	void stringup();
	//d.提供一个这样的成员函数,它接受一个char参数,返回该字符在字符串中出现的次数
	int has(char ch);
};
#endif // !STRING1_H_

2.2string.cpp

#include <cstring>
#include <cctype>
#include "string122.h"
using std::cin;
using std::cout;

int String::num_strings = 0;
//static method
int String::Howmany()
{
	return num_strings;
}
String::String(const char* s)
{
	len = std::strlen(s);
	str = new char[len + 1];
	strcpy_s(str,len+1, s);
	num_strings++;
}
String::String()
{
	len = 4;
	str = new char[1];
	str[0] = '\0';
	num_strings++;
}
String::String(const String&st)
{
	num_strings++;
	len = st.len;
	str = new char[len + 1];
	strcpy_s(str,len+1, st.str);
}
String::~String()
{
	--num_strings;
	delete[] str;
}

//重载
String& String::operator=(const String& st)
{
	if (this == &st)
		return *this;
	delete[] str;
	len = st.len;
	str = new char[len + 1];
    strcpy_s(str,len+1, st.str);
	return *this;
}
String& String::operator=(const char* s)
{
	delete[] str;
	len = std::strlen(s);
	str = new char[len + 1];
	strcpy_s(str, len+1,s);
	return *this;
}
char& String:: operator[](int i)
{
	return str[i];
}
const char& String::operator[](int i)const
{
	return str[i];
}
//友元
bool operator<(const String& st1, const String& st2)
{
	return(std::strcmp(st1.str, st2.str));
}
bool operator>(const String& st1, const String& st2)
{
	return st2 < st1;
}
bool operator==(const String& st1, const String& st2)
{
	return(std::strcmp(st1.str, st2.str) == 0);
}
ostream& operator<<(ostream& os, const String& st)
{
	os << st.str;
	return os;
}
istream& operator>>(istream& is, String& st)
{
	char temp[String::CINLIM];
	is.get(temp,String::CINLIM);
	if (is)
		st = temp;
	while (is && is.get() != '\n')
		continue;
	return is;
}
//新增函数

String String::operator+(const String& s)const
{
	int lens = s.len + len;
	char* temp = new char[lens + 1];
	strcpy(temp, str);
	strcpy(temp+len, s.str);  //注意!!!
	return String(temp);
}
String String::operator+(const char* s)const
{
	int lens = strlen(s) + len;
	char* temp = new char[lens + 1];
	strcpy(temp, str);
	strcpy(temp+len,s);
	return String(temp);
}
String operator+(const char* s1, const String& s2)
{
	return String(s1) + s2;
 }
//b.提供一个Stringlow()成员函数,将字符串中所有的字母字符转换为小写。
void String::stringlow()
{
	for (int i = 0; i <= len; i++)
	{
		str[i] = tolower(str[i]);
	}
}
//c.提供String()成员函数,将字符串中所有字母字符转换成大写。
void String::stringup()
{
	for (int i = 0; i <= len; i++)
	{
		str[i] = toupper(str[i]);
	}
}
//d.提供一个这样的成员函数,它接受一个char参数,返回该字符在字符串中出现的次数
int String::has(char ch)
{
	int count = 0;
	for (int i = 0; i <= len; i++)
	{
		if (str[i] == ch)
			count++;
	}
	return count;
}

 2.3测试类.cpp

#include <iostream>
using namespace std;
#include "string122.h"
int main()
{
	String s1(" and I am a C++ student.");
	String s2 = "Please enter your name: ";
	String s3;
	cout << s2;
	cin >> s3;
	s2 = "My name is " + s3;
	cout << s2 << ".\n";
	s2 = s2 + s1;
	s2.stringup();
	cout << "The string\n" << s2 << "\ncontains " << s2.has('A')
		<< " 'A' characters in it.\n";
	s1 = "red";
	String rgb[3] = { String(s1),String("green"),String("blue") };
	cout << "Enter the name of a primary color for mixing light: ";
	String ans;
	bool success = false;
	while (cin >> ans)
	{
		ans.stringlow();
		for (int i = 0; i < 3; i++)
		{
			if (ans == rgb[i])
			{
				cout << "That's right!\n";
				success = true;
				break;
			}
		}
		if (success)
			break;
		else
			cout << "Try again!\n";
	}
	cout << "Bye\n";
	return 0;
}

3.新编写程序清单10.7和程序清单10.8描述的Stock类,使之使用动态内存分配的内存,而不是string类对象来存储股票名称。另外,使用重载的operator<<()定义代替show()成员函数。再使用程序清单10.9测试新的定义程序。

3.1头文件stock123.h

#ifndef STOCK123_H_
#define STOCK123_H_
#pragma warning(disable:4996)   
#include <iostream>
using std::ostream;
class Stock
{
private:
	char* company;
	int shares;
	double share_val;
	double total_val;
	void set_tot() { total_val = shares * share_val; }
public:
    Stock();                 // default constructor
    Stock(const char* co, long n = 0, double pr = 0.0);
    ~Stock();               
    void buy(long num, double price);
    void sell(long num, double price);
    void update(double price);
    friend ostream& operator<<(ostream& os, const Stock& st);
    const Stock& topval(const Stock& s) const;
};
#endif // !STOCK123_H_

3.2类定义.cpp

#include <iostream>
#include "stock123.h"
#include <cstring>
using namespace std;

Stock::Stock()
{
    company = new char[strlen("no name") + 1];
    strcpy(company, "no name");
    shares = 0;
    share_val = 0.0;
    total_val = 0.0;
}
Stock::Stock(const char* co, long n, double pr)
{
    company = new char[strlen(co) + 1];
    strcpy(company, co);
    if (n < 0)
    {
        cout << "Number of shares can't be negative; "
            << company << " shares set to 0.\n";
        shares = 0;
    }
    else
        shares = n;
    share_val = pr;
    set_tot();
}
Stock::~Stock()
{
    delete[] company;
}
void Stock::buy(long num, double price)
{
    if (num < 0)
    {
        std::cout << "Number of shares purchased can't be negative. "
            << "Transaction is aborted.\n";
    }
    else
    {
        shares += num;
        share_val = price;
        set_tot();
    }
}
void Stock::sell(long num, double price)
{
    if (num < 0)
    {
        cout << "Number of shares sold can't be negative. "
            << "Transaction is aborted.\n";
    }
    else if (num > shares)
    {
        cout << "You can't sell more than you have! "
            << "Transaction is aborted.\n";
    }
    else
    {
        shares -= num;
        share_val = price;
        set_tot();
    }
}
void Stock::update(double price)
{
    share_val = price;
    set_tot();
}
ostream& operator<<(ostream& os, const Stock& st)
{
    ios_base::fmtflags orig =
        os.setf(ios_base::fixed, ios_base::floatfield);
    std::streamsize prec = os.precision(3);

    os << "Company: " << st.company
        << "  Shares: " << st.shares << '\n';
    os << "  Share Price: $" << st.share_val;
    // set format to #.##
    os.precision(2);
    os << "  Total Worth: $" << st.total_val << '\n';

    // restore original format
    os.setf(orig, ios_base::floatfield);
    os.precision(prec);
    return os;
}
const Stock& Stock::topval(const Stock& s) const
{
    if (s.total_val > total_val)
        return s;
    else
        return *this;
}

3.3测试类.cpp

#include <iostream>
#include "stock123.h"

const int STKS = 4;
int main()
{
    {
        // create an array of initialized objects
        Stock stocks[STKS] = {
            Stock("NanoSmart", 12, 20.0),
            Stock("Boffo Objects", 200, 2.0),
            Stock("Monolithic Obelisks", 130, 3.25),
            Stock("Fleep Enterprises", 60, 6.5)
        };

        std::cout << "Stock holdings:\n";
        int st;
        for (st = 0; st < STKS; st++)
            std::cout << stocks[st];
        // set pointer to first element
        const Stock* top = &stocks[0];
        for (st = 1; st < STKS; st++)
            top = &top->topval(stocks[st]);
        // now top points to the most valuable holding
        std::cout << "\nMost valuable holding:\n";
        std::cout << *top; }
    
    return 0;
}

4.请看下面程序清单10.10定义的Stack类的变量:

(……代码忽略……)

正如私有成员表明的,这个类使用动态内存分配的数组来保存栈项。请重新编写方法,以适应这种新的表示法,并编写一个程序来演示所有的方法,包括复制构造函数和赋值运算符。

4.1头文件stack.h

#ifndef STACK124_H_
#define STACK124_H_

typedef unsigned long Item;

class Stack
{
private:
    enum { MAX = 10 };    // constant specific to class
    Item* pitems;      // holds stack items
    int size;
    int top;          // index for top stack item
public:
    Stack(int n = MAX);
    Stack(const Stack& st);
    ~Stack();
    bool isempty() const;
    bool isfull() const;
    // push() returns false if stack already is full, true otherwise
    bool push(const Item& item);   // add item to stack
    // pop() returns false if stack already is empty, true otherwise
    bool pop(Item& item);          // pop top into item
    Stack& operator=(const Stack& st);
};
#endif

4.2成员函数定义.cpp

#include <iostream>
#include "stack124.h"

Stack::Stack(int n)
{
	pitems = new Item[n];
	size = n;
	top = 0;
}
Stack::Stack(const Stack& st)
{
	size = st.size;
	pitems = new Item[size];
	for (int i = 0; i < size; i++)
	{
		pitems[i] = st.pitems[i];
	}
	top = st.top;
}
Stack::~Stack()
{
	delete[] pitems;
}
bool Stack::isempty() const
{
	return top == 0;
}
bool Stack::isfull() const
{
	return top == MAX;
}
// push() returns false if stack already is full, true otherwise
bool Stack::push(const Item& item) // add item to stack
{
	if (top < MAX)
	{
		pitems[top++] = item;
		return true;
	}
	else
		return false;
}
// pop() returns false if stack already is empty, true otherwise
bool Stack::pop(Item& item)       // pop top into item
{
	if (top > 0)
	{
		item = pitems[--top];
		return true;
	}
	else
		return false;
}
Stack& Stack::operator=(const Stack& st)
{
	if (this == &st)
		return *this;
	delete[]pitems;
	size = st.size;
	pitems = new Item[size];
	for (int i = 0; i < size; i++)
	{
		pitems[i] = st.pitems[i];
	}
	top = st.top;
	return *this;
}

4.3 使用类.cpp

#include <iostream>
#include "stack124.h"
using namespace std;

int main(void)
{
	Stack st1;
	Stack st2;
	Item p1[10] = { 12,20,3,0,2,2,3,5,8,9 };
	for (int i = 0; i < 10; i++)
	{
		st2.push(p1[i]);
		cout << p1[i]<<" ";
	}
	cout << endl;
	cout << "Is st2 empty: " << st2.isempty() << endl;
	cout << "Is st2 full: " << st2.isfull() << endl;

	st1 = st2;
	cout << "st1赋值后:" << endl;
	cout << "Is st1 empty: " << st1.isempty() << endl;
	cout << "Is st1 full: " << st1.isfull() << endl;

	Stack st3(st2);
	cout << "用st2构造st3后:" << endl;
	cout << "Is st3 empty: " << st3.isempty() << endl;
	cout << "Is st3 full: " << st3.isfull() << endl;

	for (int i = 0; i < 10; i++)
	{
		st2.pop(p1[i]);
		cout << p1[i] << " ";
	}
	cout << endl;
	cout << "st2全pop后:" << endl;
	cout << "Is st2 empty: " << st2.isempty() << endl;
	cout << "Is st2 full: " << st2.isfull() << endl;
	for (int i = 0; i < 6; i++)
	{
		st3.pop(p1[i]);
		cout << p1[i] << " ";
	}
	cout << endl;
	cout << "st3部分pop后:" << endl;
	cout << "Is st3 empty: " << st3.isempty() << endl;
	cout << "Is st3 full: " << st3.isfull() << endl;
	system("pause");
	return 0;
}

5.Heather银行进行的研究表明,ATM客户不希望排队时间不超过1分钟。使用程序清单12.10中的模拟,找出要使平均等候时间为1分钟,每小时到达的客户数应为多少(试验时间不短于100小时)?

6.Heather银行想知道,如果再开设一台ATM,情况将如何。请对模拟进行修改,以包含两个队列。假设当第一台ATM前的排队人数少于第二台ATM时,客户将排在第一队,否则将排在第二队。然后再找出要使平均等候时间为1分钟,每小时到达的客户数应该为多少(注意,这是一个非线性问题,即将ATM数量加倍,并不能保证每小时处理的客户数量也翻倍,并确保客户等候的时间少于1分钟)?

5.6不会不想做。参考https://www.manongdao.com/article-172261.html

第13章 类继承

1.

1.以下面的类声明为基础:

class Cd {                    //represents a CD disk
private:
    char performers[50];
    char label[20];
    int selections;          //number of selections
    double playtime;        //playing time in minute
public:
    Cd(char* s1, char* s2, int n, double x);
    Cd(const Cd& d);
    Cd();
    ~Cd();
    void Report() const; //reports all CD data
    Cd& operator=(const Cd& d);
};

派生出一个Classic类,并添加一组char成员,用于存储指出CD中主要作品的字符串。修改上述声明,使基类的搜有函数都是虚的。如果上述定义声明的某个方法并不需要,则请删除它。使用下面的程序测试您的产品:

#include<iostream>
using namespace std;
#include"cd131.h"

void Bravo(const Cd& disk);
int main()
{
    Cd c1("beatles", "Capitol", 14, 35.5);
    Classic c2 = Classic("Piano Sonata in B flat, Fantasia in C", "Alfred Brendel", "Philips", 2, 57.17);
    Cd* pcd = &c1;
    cout << "Using object directly:\n";
    c1.Report(); //use Cd method
    c2.Report(); //use Classic method
    cout << "Using type cd *pointer to objects:\n";
    pcd->Report(); //use Cd method for cd object
    pcd = &c2;
    pcd->Report(); //use Classic method for classic object
    cout << "Calling a function with a Cd reference argument:\n";
    Bravo(c1);
    Bravo(c2);
    cout << "Testing assignment: ";
    Classic copy;
    copy = c2;
    copy.Report();
    return 0;
}

void Bravo(const Cd& disk)
{
    disk.Report();
}

答:

1.1头文件cd131.h

#ifndef CD131_H_
#define CD131_H_
#pragma warning(disable:4996)
class Cd {                    //represents a CD disk
private:
    char performers[50];
    char label[20];
    int selections;          //number of selections
    double playtime;        //playing time in minute
public:
    Cd(const char * s1,const char* s2, int n, double x);
    Cd(const Cd& d);
    Cd();
    virtual ~Cd();
    virtual void Report() const; //reports all CD data
    virtual Cd& operator=(const Cd& d);
};

class Classic : public Cd
{
private:
    char mainworks[50];
public:
    Classic(const char* m,const char* s1,const char* s2, int n, double x);
    Classic(const char* m,const Cd& rs);
    Classic();
    virtual ~Classic();
    virtual void Report() const;
    virtual Classic& operator=(const Classic& d);
};

#endif // !CD131_H_

1.2类函数定义.cpp

#include "cd131.h"
#include <iostream>
using namespace std;
#include <cstring>
#include <cstdlib>
Cd::Cd(const char* s1,const char* s2, int n, double x)
{
	strncpy(performers, s1,49);
	performers[49] = '\0';
	strncpy(label, s2, 19);
	label[19] = '\0';
	selections = n;
	playtime = x;
}
Cd::Cd(const Cd& d)
{
	strncpy(performers, d.performers, 49);
	performers[49] = '\0';
	strncpy(label, d.performers, 19);
	label[19] = '\0';
	selections = d.selections;
	playtime = d.playtime;
}
Cd::Cd()
{
	strcpy(performers,"null");
	strcpy(label,"null");
	selections = 0;
	playtime = 0.0;
}
Cd::~Cd()
{

}
void Cd::Report() const //reports all CD data
{
	cout << "Performers: " << performers << endl;
	cout << "Label: " << label << endl;
	cout << "There are " << selections << " selections and lasts " << playtime << " minutes.\n";
}
Cd& Cd::operator=(const Cd& d)
{
	strncpy(performers, d.performers, 49);
	performers[49] = '\0';
	strncpy(label, d.performers, 19);
	label[19] = '\0';
	selections = d.selections;
	playtime = d.playtime;
	return *this;
}

Classic::Classic(const char* m, const char* s1,const  char* s2, int n, double x):Cd(s1, s2, n, x)
{
	strncpy(mainworks,m, 49);
	mainworks[49] = '\0';
}
Classic::Classic(const char* m,const Cd& rs) : Cd(rs)
{
	strncpy(mainworks, m, 49);
	mainworks[49] = '\0';
}
Classic::Classic() : Cd()
{
	strcpy(mainworks,"null");
}
Classic::~Classic()
{

}
void Classic::Report() const
{
	Cd::Report();
	cout << "The main works of this disk are " << mainworks << endl;
}
Classic& Classic::operator=(const Classic& d)
{
	if (this == &d)
		return *this;
	Cd::operator=(d);
	strncpy(mainworks, d.mainworks,49);
	mainworks[49] = '\0';
	return *this;
}

1.3测试类.cpp

#include<iostream>
using namespace std;
#include"cd131.h" //which will contain #include cd.h

void Bravo(const Cd& disk);
int main()
{
	Cd c1("beatles", "Capitol", 14, 35.5);
	Classic c2 = Classic("Piano Sonata in B flat, Fantasia in C", "Alfred Brendel", "Philips", 2, 57.17);
	Cd* pcd = &c1;
	cout << "Using object directly:\n";
	c1.Report(); //use Cd method
	c2.Report(); //use Classic method
	cout << "Using type cd *pointer to objects:\n";
	pcd->Report(); //use Cd method for cd object
	pcd = &c2;
	pcd->Report(); //use Classic method for classic object
	cout << "Calling a function with a Cd reference argument:\n";
	Bravo(c1);
	Bravo(c2);
	cout << "Testing assignment: ";
	Classic copy;
	copy = c2;
	copy.Report();
	return 0;
}

void Bravo(const Cd& disk)
{
	disk.Report();
}

2..完成练习1,但让两个类使用动态内存分配而不是长度固定的数组来记录字符串。

答:

2.1头文件“cd132.h”(与上题相比,仅仅把数组改成指针形式)

#ifndef CD132_H_
#define CD132_H_
#pragma warning(disable:4996)
class Cd {                    //represents a CD disk
private:
    char* performers;
    char* label;
    int selections;          //number of selections
    double playtime;        //playing time in minute
public:
    Cd(const char* s1, const char* s2, int n, double x);
    Cd(const Cd& d);
    Cd();
    virtual ~Cd();
    virtual void Report() const; //reports all CD data
    virtual Cd& operator=(const Cd& d);
};

class Classic : public Cd
{
private:
    char* mainworks;
public:
    Classic(const char* m, const char* s1, const char* s2, int n, double x);
    Classic(const char* m, const Cd& rs);
    Classic();
    virtual ~Classic();
    virtual void Report() const;
    virtual Classic& operator=(const Classic& d);
};

#endif // !CD131_H_

2.2类函数定义.cpp(有变化)

#include "cd132.h"
#include <iostream>
using namespace std;
#include <cstring>
#include <cstdlib>
Cd::Cd(const char* s1, const char* s2, int n, double x)
{
	performers = new char[strlen(s1) + 1];
	strcpy(performers, s1);
	label = new char[strlen(s2) + 1];
	strcpy(label, s2);
	selections = n;
	playtime = x;
}
Cd::Cd(const Cd& d)
{
	performers = new char[strlen(d.performers) + 1];
	strcpy(performers, d.performers);
	label = new char[strlen(d.label) + 1];
	strcpy(label, d.label);
	selections = d.selections;
	playtime = d.playtime;
}
Cd::Cd()
{
	performers = new char[5];
	strcpy(performers, "null");
	label = new char[5];
	strcpy(label, "null");
	selections = 0;
	playtime = 0.0;
}
Cd::~Cd()
{
	delete[] performers;
	delete[] label;
}
void Cd::Report() const //reports all CD data
{
	cout << "Performers: " << performers << endl;
	cout << "Label: " << label << endl;
	cout << "There are " << selections << " selections and lasts " << playtime << " minutes.\n";
}
Cd& Cd::operator=(const Cd& d)
{
	performers = new char[strlen(d.performers) + 1];
	strcpy(performers, d.performers);
	label = new char[strlen(d.label) + 1];
	strcpy(label, d.label);
	selections = d.selections;
	playtime = d.playtime;
	return *this;
}

Classic::Classic(const char* m, const char* s1, const  char* s2, int n, double x) :Cd(s1, s2, n, x)
{
	mainworks = new char[strlen(m) + 1];
	strcpy(mainworks, m);
}
Classic::Classic(const char* m, const Cd& rs) : Cd(rs)
{
	mainworks = new char[strlen(m) + 1];
	strcpy(mainworks, m);
}
Classic::Classic() : Cd()
{
	mainworks = new char[5];
	strcpy(mainworks, "null");
}
Classic::~Classic()
{
	delete[] mainworks;
}
void Classic::Report() const
{
	Cd::Report();
	cout << "The main works of this disk are " << mainworks << endl;
}
Classic& Classic::operator=(const Classic& d)
{
	if (this == &d)
		return *this;
	Cd::operator=(d);
	mainworks = new char[strlen(d.mainworks) + 1];
	strcpy(mainworks, d.mainworks);
	return *this;
}

2.3类测试.cpp(与上题相同,无变化)

#include<iostream>
using namespace std;
#include"cd132.h" //which will contain #include cd.h

void Bravo(const Cd& disk);
int main()
{
	Cd c1("beatles", "Capitol", 14, 35.5);
	Classic c2 = Classic("Piano Sonata in B flat, Fantasia in C", "Alfred Brendel", "Philips", 2, 57.17);
	Cd* pcd = &c1;
	cout << "Using object directly:\n";
	c1.Report(); //use Cd method
	c2.Report(); //use Classic method
	cout << "Using type cd *pointer to objects:\n";
	pcd->Report(); //use Cd method for cd object
	pcd = &c2;
	pcd->Report(); //use Classic method for classic object
	cout << "Calling a function with a Cd reference argument:\n";
	Bravo(c1);
	Bravo(c2);
	cout << "Testing assignment: ";
	Classic copy;
	copy = c2;
	copy.Report();
	return 0;
}

void Bravo(const Cd& disk)
{
	disk.Report();
}

3.修改baseDMA-lacksDMA-hasDMA类层次,让三个类都从一个ABC派生而来,然后使用与程序清单13.10相似的程序对结果进行测试。也就是说,它应使用ABC指针数组,并让用户决定要创建的对象类型。在类定义中添加virtual View()方法以处理数据显示。

答:

3.1头文件dma133.h

#ifndef  ABC133_H_
#define ABC133_H_
#include <iostream>
#pragma warning(disable:4996)

class ABC
{
public:
	ABC() {};
	~ABC() {};
	virtual void View() = 0;
};
//Baseclass using DMA
class baseDMA:public ABC
{
private:
	char* label;
	int rating;
public:
	baseDMA(const char* l = "null", int r = 0);
	baseDMA(const baseDMA& rs);
	virtual ~baseDMA();
	baseDMA& operator=(const baseDMA& rs);
	friend std::ostream& operator<<(std::ostream& os, const baseDMA& rs);
	virtual void View();
};

class lacksDMA :public baseDMA
{
private:
	enum { COL_LEN = 40 };
	char color[COL_LEN];
public:
	lacksDMA(const char* c = "blank", const char* l = "null", int r = 0);
	lacksDMA(const char* c, const baseDMA& rs);
	friend std::ostream& operator<<(std::ostream& os, const lacksDMA& rs);
	virtual void View();
};
class hasDMA :public baseDMA
{
private:
	char* style;
public:
	hasDMA(const char* s = "none", const char* l = "null", int r = 0);
	hasDMA(const char* s, const baseDMA& rs);
	hasDMA(const hasDMA& hs);
	~hasDMA();
	hasDMA& operator= (const hasDMA& hs);
	friend std::ostream& operator<<(std::ostream& os, const hasDMA& hs);
	virtual void View();
};

#endif // ! ABC

3.2类成员函数定义.cpp

#include "ABC133.h"
#include <cstring>


//Baseclass methods
baseDMA::baseDMA(const char* l, int r)
{
	label = new char[std::strlen(l) + 1];
	std::strcpy(label, l);
	rating = r;
}
baseDMA::baseDMA(const baseDMA& rs)
{
	label = new char[std::strlen(rs.label) + 1];
	std::strcpy(label, rs.label);
	rating = rs.rating;
}
baseDMA::~baseDMA()
{
	delete[] label;
}
baseDMA& baseDMA::operator=(const baseDMA& rs)
{
	if (this == &rs)
		return *this;
	delete[] label;
	label = new char[std::strlen(rs.label) + 1];
	strcpy(label, rs.label);
	rating = rs.rating;
	return *this;
}
std::ostream& operator<<(std::ostream& os, const baseDMA& rs)
{
	os << "Label: " << rs.label << std::endl;
	os << "Rating: " << rs.rating << std::endl;
	return os;
}
void baseDMA::View()
{
	std::cout<< "Label: " << label << std::endl;
	std::cout<< "Rating: " << rating << std::endl;
}

//lacksDMA methods
lacksDMA::lacksDMA(const char* c, const char* l, int r) :baseDMA(l, r)
{
	std::strncpy(color, c, 39); //用于指定长度的字符串赋值到字符数组中
	color[39] = '\0';
}
lacksDMA::lacksDMA(const char* c, const baseDMA& rs) : baseDMA(rs)
{
	std::strncpy(color, c, COL_LEN - 1);
	color[COL_LEN - 1] = '\0';
}
std::ostream& operator<<(std::ostream& os, const lacksDMA& ls)
{
	os << (const baseDMA&)ls;
	os << "Color: " << ls.color << std::endl;
	return os;
}
void lacksDMA::View()
{
	baseDMA::View();
	std::cout << "Color: " <<color <<std:: endl;
}

//hasDMA mmethods
hasDMA::hasDMA(const char* s, const char* l, int r) :baseDMA(l, r)
{
	style = new char[std::strlen(s) + 1];
	std::strcpy(style, s);
}
hasDMA::hasDMA(const char* s, const baseDMA& rs) : baseDMA(rs)
{
	style = new char[std::strlen(s) + 1];
	std::strcpy(style, s);
}
hasDMA::hasDMA(const hasDMA& hs) : baseDMA(hs)
{
	style = new char[std::strlen(hs.style) + 1];
	std::strcpy(style, hs.style);
}
hasDMA::~hasDMA()
{
	delete[]style;
}
hasDMA& hasDMA::operator= (const hasDMA& hs)
{
	if (this == &hs)
		return *this;
	baseDMA::operator=(hs);
	delete[]style;
	style = new char[std::strlen(hs.style) + 1];
	std::strcpy(style, hs.style);
	return *this;
}
std::ostream& operator<<(std::ostream& os, const hasDMA& hs)
{
	os << (const baseDMA&)hs;
	os << "Style: " << hs.style << std::endl;
	return os;
}
void hasDMA::View()
{
	baseDMA::View();
	std::cout << "Style: " << style << std::endl;
}

3.3测试类.cpp

#include <iostream>
#include <string>
#include "ABC133.h"
using namespace std;
const int DMA = 6;

int main(void)
{
	using std::cin;
	using std::cout;
	using std::endl;

	ABC * p_dma[DMA];
	char *templabel = new char[50];
	int temprating;
	
	char kind;
	
	for (int i = 0; i < DMA; i++)
	{
		cout << "Enter label: ";
		cin.getline(templabel, 50);
		cout << "Enter rating: ";
		cin >> temprating;
		cout << "Enter 1 for baseDMA or 2 for lacksDMA or 3 for hasDMA: ";
		while (cin >> kind && kind != '1' && kind != '2' && kind!='3')
			cout << "Enter either 1 or 2 or 3: ";
		cin.ignore();      //这里很重要,墨迹了好久才解决呜呜,长记性啊!!!
		if (kind == '1')
		{
			p_dma[i] = new baseDMA(templabel, temprating);
		}
		else if(kind  == '2')
		{
			char tempcolor[40];
			cout << "Enter color: ";
			cin.getline(tempcolor, 40);
			p_dma[i] = new lacksDMA(tempcolor,templabel, temprating);
		}
		else
		{
			char *tempstyle = new char[20];
			cout << "Enter style: ";
			cin.getline(tempstyle, 20);
			p_dma[i] = new hasDMA(tempstyle, templabel, temprating);
		}
		while (cin.get() != '\n')
			continue;
	}
	cout << endl;
	for (int i = 0; i < DMA; i++)
	{
		p_dma[i]->View();
		cout << endl;
	}

	for (int i = 0; i < DMA; i++)
	{
		delete p_dma[i];
	}
	cout << "Done.\n" << endl;

	

	system("pause");
	return 0;
}

4.

4.Benevolent Order of Programmers用来维护瓶装葡萄酒箱。为描述它,BOP Portmaster设置了一个Port类,并声明如下:

#include<iostream>
using namespace std;
class Port
{
private:
    char* brand;
    char style[20]; //i.e., tawny, ruby, vintage
    int bottles;

public:
    Port(const char* br = "none", const char* st = "none", int b = 0);
    Port(const Port& p); //copy constructor
    virtual ~Port() { delete[] brand; }
    Port& operator=(const Port& p);
    Port& operator+=(int b); //add b to bottles
    Port& operator-=(int b); //subtracts b from bottles , if available
    int BottleCount() const { return bottles; }
    virtual void Show() const;
    friend ostream& operator<<(ostream & os, const Port & p);
    };
show()方法按下面的格式显示信息:
Brand : Gallo
Kind : tawny
Bottles : 20

operator<<()函数按下面的格式显示信息(末尾没有换行符):
Gallo, tawny, 20
PortMaster完成了Port类的方法定义后派生了VintagePort类,然后被解职——因为不小心将一瓶45度Cockburn泼到了正在准备烤肉调料的人身上,VintagePort类如下显示:
class VintagePort : public Port //style necessarily = "vintage"
{
private:
    char* nickname; //i.e. , "The Noble" or "Old Velvet", etc.
    int year; //vintage year
public:
    VintagePort();
    VintagePort(const char* br, const char* st, int b, const char* nn, int y);
    VintagePort(const VintagePort& vp);
    ~VintagePort() { delete[] nickname; }
    VintagePort& operator = (const VintagePort& vp);
    void show() const;
    friend ostream& operator <<(ostream& os, const VintagePort& vp);
};
您被制定指定负责完成VintagePort。
a.第一个任务是重新创建Port方法定义,因为前任被开除时销毁了方法定义。
b.第二个任务是解释为什么有的方法重新定义了,而有些没有重新定义。
c.第三个任务解释为何没有将operator = () 和operator << ()声明为虚的。
d.第四个任务是提供VintagePort中各个方法的定义。

答:

a.第一个任务是重新创建Port方法定义,因为前任被开除时销毁了方法定义。

Port::Port(const char* br, const char* st, int b )
{
	brand = new char[strlen(br) + 1];
	strcpy(brand, br);
	strcpy(style, st);
	bottles = b;
}
Port::Port(const Port& p) //copy constructor
{
	brand = new char[strlen(p.brand) + 1];
	strcpy(brand, p.brand);
	strcpy(style, p.style);
	bottles = p.bottles;
}
Port& Port::operator=(const Port& p)
{
	if (this == &p)
		return *this;
	delete[]brand;
	brand = new char[strlen(p.brand) + 1];
	strcpy(brand, p.brand);
	strcpy(style, p.style);
	bottles = p.bottles;
	return *this;
}
Port& Port::operator+=(int b)//add b to bottles
{
	bottles += b;
	return *this;
}
Port& Port::operator-=(int b) //subtracts b from bottles , if available
{
	bottles -= b;
	return *this;
}
void Port::Show() const
{
	cout << "Brand: " << brand << endl;
	cout << "Kind: " << style << endl;
	cout << "Bottles: " << bottles << endl;
}
ostream& operator<<(ostream& os, const Port& p)
{
	os << p.brand << "," << p.style << ","<<p.bottles;
}

b.第二个任务是解释为什么有的方法重新定义了,而有些没有重新定义。

当派生类成员函数需要处理派生类独有的成员变量时,需要重新定义方法,如果不需要处理派生类独有的成员变量,直接调用基类的方法即可。
c.第三个任务解释为何没有将operator = () 和operator << ()声明为虚的。

a).如果要在派生类中重新定义基类的方法,则将它设置为虚方法。但是基类的operator = () 和派生类的operator = () 形参不一样,根本不是一个类方法,不存在重新定义的问题,因从也不必声明为虚的。

b).operator<<()函数是友元函数,友元函数不能是虚函数,因为友元不是类成员,而只有类成员才能是虚函数。
d.第四个任务是提供VintagePort中各个方法的定义。

VintagePort::VintagePort():Port()
{

}
VintagePort::VintagePort(const char* br, const char* st, int b, const char* nn, int y)
	: Port(br, st, b)
{
	nickname = new char[strlen(nn) + 1];
	strcpy(nickname, nn);
	int year = y;
}
VintagePort::VintagePort(const VintagePort& vp):Port(vp)
{
	nickname = new char[strlen(vp.nickname) + 1];
	strcpy(nickname, vp.nickname);
	int year = vp.year;
}
VintagePort& VintagePort::operator = (const VintagePort& vp)
{
	if (this == &vp)
		return *this;
	Port::operator=(vp);
	delete[]nickname;
	nickname = new char[strlen(vp.nickname) + 1];
	strcpy(nickname, vp.nickname);
	strcpy(nickname, vp.nickname);
	year = vp.year;
	return *this;
}
void VintagePort::show() const
{
	Port::Show();
	cout << "nickname: " << nickname << endl;
	cout << "year: " << year << endl;
}
ostream& operator <<(ostream& os, const VintagePort& vp)
{
	os << (const Port&)vp;
	os << vp.nickname << "," << vp.year ;
	return os;
}

第14章 C++中的代码重用

1.

1.Wine类有一个string类对象成员(参见第4章)和一个Pair对象(参见本章):其中前者用来存储葡萄酒的名称,而后者有2个valarry<int>对象(参见本章),这两个valarry<int>对象分别保存了葡萄酒的酿造年份和该年生产的瓶数。例如,Pair的第1个valarray<int>对象可能为1988、1992和1996,第二个valarry<int> 对象可能为24、48和144瓶。Wine最好有1个int成员用于存储年数。另外,一些typedef可能有助于简化编程工作:

typedef std::valarry<int> ArrayInt;
typedef Pair<ArrayInt, ArrayInt> PairArray;
这样,PairArray表示的类型是Pair<std::valarry<int>,std::valarray<int>>。使用包含来实现Wine类,并用一个简单的程序对其进行测试。Wine类应该有一个默认构造函数以及如下的构造函数:
Wine(const char* l, int y, const int yr[], ocnst int bot[]);
Wine(const char* l, int y);
Wine类应该有一个GetBottles()方法,它根据Wine对象能够存储集中年份(y),提示用户输入年份和瓶数。方法Label()返回一个指向葡萄酒名称的引用。sum()方法返回Pair对象中第二个valarray<int>对象中的瓶数总和。

测试程序应提示用户输入葡萄酒名称、元素个数以及每个元素存储的年份和瓶数等信息。程序将使用这些数据来构造一个Wine对象,然后显示对象中保存的信息。

下面是一个简单的测试程序:

int main()

{
    cout << "Enter name of wine: ";
    char lab[50];
    cin.getline(lab, 50);
    cout << "Enter number of years: ";
    int yrs;
    cin >> yrs;
    
    Wine holding(lab, yrs);
    holding.GetBottles();
    holding.Show();
    
    const int YRS = 3;
    int y[YRS] = {1993, 1995, 1998};
    int b[YRS] = {48, 60, 72};
    Wine more("Gushing Grape  Red", YRS, y, b);
    more.Show();
    cout << "Total bottle for " << more.Label()
    <<": " << more.sum() << endl;
    cout << "Bye\n";
    
    return 0;
}
下面是该程序的运行情况:

Enter name of wine: Gully Wash

Enter number of years: 4

Enter Gully Wash data for 4 year(s):

Enter year: 1988

Enter bottles for that year: 42

Enter year: 1994

Enter bottles for that year: 58

Enter year: 1998

Enter bottles for that year: 122

Enter year: 2001

Enter bottles for that year: 144

Wine: Gully Wash

Year Bottles

1988 42

1994 58

1998 122

2001 144

Wine: Gushing Grape  Red

Year Bottles

1993 48

1995 60

1998 72

Total bottle for Gushing Grape  Red: 180

Bye

答:

1.1头文件winec.h

#ifndef WINEC141_H_
#define WINEC141_H_
#include <iostream>
#include <string>
#include <valarray>

template<class T1,class T2>
class Pair
{
private:
	T1 a;
	T2 b;
public:
	Pair(const T1& aval, const T2& bval) :a(aval), b(bval) {}
	Pair() {}
	void set(const T1& yr, const T2& bot);
	int sum() const;
	void Show(int y) const;
};
typedef std::valarray<int> ArrayInt;
typedef Pair<ArrayInt, ArrayInt> PairArray;
class Wine
{
private:
	std::string name;
	PairArray b;
	int yrs;
public:
	Wine(const char* l, int y, const int yr[], const int bot[]);
	Wine(const char* l, int y);
	void GetBottles();
	std::string& Label();
	int sum()const;
	void Show()const;
};
#endif // !WINEC141_H_

1.2wine.cpp

#include <iostream>
#include "winec141.h"
#include <string>
#include <valarray>
using namespace std;

template<class T1,class T2>
void Pair<T1, T2>::set(const T1& yr, const T2& bot)
{
	a = yr;
	b = bot;
}
template<class T1, class T2>
int Pair<T1, T2>::sum() const
{
	return b.sum();
}
template<class T1, class T2>
void Pair<T1, T2>::Show(int y) const
{
	for (int i = 0; i < y; i++)
	{
		cout << "\t\t" << a[i] << "\t\t" << b[i] << endl;
	}
}

Wine::Wine(const char* l, int y, const int yr[], const int bot[])
{
	name = l;
	yrs = y;
	b.set(ArrayInt(yr, yrs), ArrayInt(bot, yrs));
}
Wine::Wine(const char* l, int y)
{
	name = l;
	yrs = y;
}
void Wine::GetBottles()
{
	ArrayInt yr(yrs), bot(yrs);
	cout << "Enter" << name << " data for " << yrs << " year(s):\n";
	for (int i = 0; i < yrs; i++)
	{
		cout << "Enter year: ";
		cin >> yr[i];
		cout << "Enter bottles for that year: ";
		cin >> bot[i];
	}
	b.set(yr, bot);
}
std::string& Wine::Label()
{
	return name;
}
int Wine::sum()const
{
	return b.sum();
}
void Wine::Show()const
{
	cout << "Wine: " << name << endl;
	cout << "\t\tYear\t\tBottles\n";
	b.Show(yrs);
}

1.3usewine.cpp

#include "winec141.h"
#include <iostream>

int main()
{
    using std::cin;
    using std::endl;
    using std::cout;
    cout << "Enter name of wine: ";
    char lab[50];
    cin.getline(lab, 50);
    cout << "Enter number of years: ";
    int yrs;
    cin >> yrs;

    Wine holding(lab, yrs);
    holding.GetBottles();
    holding.Show();

    const int YRS = 3;
    int y[YRS] = { 1993, 1995, 1998 };
    int b[YRS] = { 48, 60, 72 };
    Wine more("Gushing Grape  Red", YRS, y, b);
    more.Show();
    cout << "Total bottle for " << more.Label()
        << ": " << more.sum() << endl;
    cout << "Bye\n";

    return 0;
}

2.

2.采用私有继承而不是包含来完成编程练习1.同样,一些typedef可能会有所帮助,另外,您可能还需要考虑诸如下面这样的语句的含义:

PairArray::operator=(PairArray(ArrayInt(), ArrayInt()));
cout << (const string&)(*this);

您设计的类应该可以使用编程练习1中的测试程序进行测试。

答:

2.1头文件winep142.h

#ifndef WINEP142_H
#define WINEP142_H
#include <iostream>
#include <string>
#include <valarray>

template<class T1,class T2>
class Pair
{
private:
	T1 a;
	T2 b;
public:
	Pair(const T1& aval, const T2& bval) :a(aval), b(bval) {}
	Pair() {}
	void set(const T1& yr, const T2& bot);
	int sum() const;
	void Show(int y) const;
};
typedef std::valarray<int> ArrayInt;
typedef Pair<ArrayInt, ArrayInt> PairArray;
class Wine : private std::string, private PairArray
{
private:
	int yrs;
public:
	Wine(const char* l,int y,const int yr[],const int bot[]);
	Wine(const char* l,int y);
	void GetBottles();
	std::string& Label();
	int sum() const;
	void Show() const;
};
#endif // !WINEP_142_H


2.2winep.cpp

#include "winep142.h"
#include <iostream>
#include <string>
#include <valarray>
using std::cin;
using std::cout;
using std::string;
using std::endl;
template<class T1, class T2>
void Pair<T1, T2>::set(const T1& yr, const T2& bot)
{
	a = yr;
	b = bot;
}

template<class T1, class T2>
int Pair<T1, T2>::sum() const
{
	return b.sum();
}
template<class T1, class T2>
void Pair<T1, T2>::Show(int y) const
{
	for (int i = 0; i < y; i++)
	{
		cout << "\t\t" << a[i] << "\t\t" << b[i] << endl;
	}
}

Wine::Wine(const char* l, int y, const int yr[], const int bot[]):
	string(l), yrs(y), PairArray(ArrayInt(yr, yrs), ArrayInt(bot, yrs))
{

}
Wine::Wine(const char* l, int y):string(l),yrs(y)
{

}
void Wine::GetBottles()
{
	ArrayInt yr(yrs), bot(yrs);
	cout << "Enter" << (const string&)(*this) << " data for " << yrs << " year(s):\n";
	for (int i = 0; i < yrs; i++)
	{
		cout << "Enter year: ";
		cin >> yr[i];
		cout << "Enter bottles for that year: ";
		cin >> bot[i];
	}
	PairArray::set(yr, bot);
}
std::string& Wine::Label()
{
	return (string&)(*this);
}
int Wine::sum() const
{
	return PairArray::sum();
}
void Wine::Show() const
{
	cout << "Wine: " << (const string&)(*this) << std::endl;
	cout << "\t\tYear\t\tBottles\n";
	PairArray::Show(yrs);
}

2.3usewinep.cpp

#include "winep142.h"
#include <iostream>

int main()
{
    using std::cin;
    using std::endl;
    using std::cout;
    cout << "Enter name of wine: ";
    char lab[50];
    cin.getline(lab, 50);
    cout << "Enter number of years: ";
    int yrs;
    cin >> yrs;

    Wine holding(lab, yrs);
    holding.GetBottles();
    holding.Show();

    const int YRS = 3;
    int y[YRS] = { 1993, 1995, 1998 };
    int b[YRS] = { 48, 60, 72 };
    Wine more("Gushing Grape  Red", YRS, y, b);
    more.Show();
    cout << "Total bottle for " << more.Label()
        << ": " << more.sum() << endl;
    cout << "Bye\n";

    return 0;
}

3.

3.定义一个QueueTp模板。然后在一个类似于程序清单14.12的程序中创建一个指向Worker的指针队列(参见程序清单14.10中的定义),并使用该队列来测试它。

4.

4.Person类保存人的名和姓。除构造函数外,它还有Show()方法,用于显示名和姓。Gunslmger类以Person类为虚基类派生而来,它包含一个Draw()成员,该方法返回一个double值,表示枪手的拔枪时间。这个类还包含一个int成员,表示枪手枪上的刻痕数。最后,这个类还包含一个Show()函数,用于显示所有这些信息。

PokerPlayer类以Person类为虚基类派生而来。它包含一个Draw()成员,该函数返回一个1~52的随机数,用于扑克牌的值(也可以用定义一个Card类,其中包含花色和面值成员,然后让Draw()返回一个Card对象)。PokerPlayer类使用Person类的show()函数。BadDude()类从Gunslinger何PokerPlayer类公有派生而来。它包含Gdraw()成员(返回坏蛋拔枪时间)和Cdraw()成员(返回下一张扑克牌),另外还有一个合适的show()函数。请定义这些类和方法以及其他必要的方法(如用于设置对象值的方法),并使用一些类似程序清单14.12的简单程序对它们进行测试。

5.

5.下面是一些类声明:

	 class AbstrEmp
	 {
	 private:
		 string _fname;
		 string _lname;
		 string _job;
	 public:
		 AbstrEmp();
		 AbstrEmp(const std::string& fn, const string& ln, const string& j);
		 virtual void showAll()const;
		 virtual void setAll();
		 friend ostream& operator<<(ostream& os, const AbstrEmp& e);
		 virtual ~AbstrEmp() = 0;
	 };
	  
	 class Employee : public AbstrEmp
	 {
	 public:
		 Employee();
		 Employee(const string& fn, const string& ln, const string& j);
		 virtual void showAll()const;
		 virtual void setAll();
	 };

	 class Manager : virtual public AbstrEmp
	 {
	 private:
		 int _inchargeof;
	 protected:
		 int inChargeOf()const
		 {
			 return _inchargeof;
		 }
		 int& inChargeOf()
		 {
			 return _inchargeof;
		 }
	 public:
		 Manager();
		 Manager(const string& fn, const string& ln, const string& j0, int ico = 0);
		 Manager(const AbstrEmp& e, int ico);
		 Manager(const Manager& m);
		 virtual void showAll()const;
		 virtual void setAll();
	 };

	 class Fink : virtual public AbstrEmp
	 {
	 private:
		 string _reportsto;
	 protected:
		 const string reportsTo() const{ return _reportsto; }
		 string& reportsTo(){ return _reportsto; }
	 public:
		 Fink();
		 Fink(const string& fn, const string& ln, const string& j, const string& rpo);
		 Fink(const AbstrEmp& e, const string& rpo);
		 Fink(const Fink& e);
		 virtual void showAll()const;
		 virtual void setAll();
	 };

	 class HighFink: public Manager, public Fink
	 {
	 public:
		 HighFink();
		 HighFink(const string& fn, const string& ln, const string& j, const string& rpo, int ico);
		 HighFink(const AbstrEmp& e, const string& rpo, int ico);
		 HighFink(const Fink& f, int ico);
		 HighFink(const Manager& m, const string& rpo);
		 HighFink(const HighFink& h);
		 virtual void showAll()const;
		 virtual void setAll();
	 };
注意,该类层次结构使用了带虚基类的MI,所以要牢记这种情况下用于构造函数初始化列表的特殊规则。还需要注意的是,有些方法被声明为保护的。这可以简化一些HighFink方法的代码(例如,如果HightFink::showAll()只是调用Fink::showAll()和Manager::showAll(),则它将调用abstr_emp::ShowAll()两次)。提供类方法的实现,并在一个程序中对这些类进行测试。下面是一个小型测试程序:
#include <iostream>     
#include "Test.h"
#include <string>
using namespace std;
using namespace FableGame;
 
int main(int argc, const char * argv[])
{
	Employee em("Trip", "Harris", "Thumper");
	cout << em << endl;
	em.showAll();
	Manager ma("Amorphia", "Spindragon", "Nuancer", 5);
	cout << ma << endl;
	ma.showAll();
	Fink fi("Matt", "Oggs", "Oiler", "Juno Barr");
	cout << fi << endl;
	fi.showAll();
	HighFink hf(ma, "Curly Kew");
	hf.showAll();
	cout << "Press a key for next phase:\n";
	cin.get();
	HighFink hf2;
	hf2.setAll();

	cout << "Using an abstr_emp * pointer:\n";
	AbstrEmp* tri[4] = { &em, &fi, &hf, &hf2 };
	for (int i = 0; i < 4; ++i)
	{
		tri[i]->showAll();
	}
	return 0;
}

为什么没有定义赋值运算符?
为什么要将ShowAll()和SetAll()定义为虚的?
为什么要将abstr_emp定义为虚基类?
为什么highfink类没有数据部分?
为什么只需一个operator << ()版本?
如果使用下面的代码替换程序的结尾部分,将会发生什么情况?

abstr_emp str[4] = {em, fi, hf, hf2};
for(int i = 0; i < 4; ++i)
    tr[i].showAll()
  • 58
    点赞
  • 286
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
《C Primer Plus第六版》是一本面向初学者的C语言教材,由Stephen Prata撰写。这本书深入浅出地介绍了C语言的基本概念、语法和应用,给读者提供了扎实的编程基础。 该书共分为27章,每章都有清晰的目标、易于理解的示例和练习题。从第一章的入门介绍开始,到最后一章的高级主题讨论,书中的内容依次递进,系统完整地覆盖了C语言的方方面面。本书有助于读者逐步掌握C语言的基础知识,从简单的输出语句到复杂的函数调用和指针使用。 《C Primer Plus第六版》的特点是其清晰的讲解风格和丰富的实例。作者通过通俗易懂的语言和生动形象的例子,帮助读者理解和掌握C语言的各种概念和语法。此外,书中还提供了许多练习题和编程项目,供读者巩固所学知识和提高编程能力。 作为一本经典的C语言教材,《C Primer Plus第六版》被广泛用于学校和个人学习。它不仅适用于初学者,也对有一定编程基础的读者有所帮助。读者通过学习本书,可以建立起对C语言编程的扎实基础,为深入学习其他编程语言打下坚实的基础。 综上所述,《C Primer Plus第六版》是一本权威、经典的C语言教材,通过清晰的讲解和丰富多样的示例帮助读者深入理解C语言的基本概念和应用。无论是初学者还是有一定编程基础的读者,都可以从中获益,打下良好的编程基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值