1. 对于下面的类声明:
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;
};
给这个类提供实现,并编写一个使用所有成员函数的小程序。
#pragma once
#ifndef COW_H_
#define COW_H_
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 // !COW_H_
// cow.cpp
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include "cow.h"
using std::strncpy;
using std::strcpy;
// 默认构造函数
Cow::Cow() {
hobby = nullptr;
weight = 0.0;
}
// 构造函数
Cow::Cow(const char* nm, const char* ho, double wt) {
strncpy(name, nm, 20);
hobby = new char[strlen(ho) + 1];
strcpy(hobby, ho);
weight = wt;
}
// 复制构造函数
Cow::Cow(const Cow& c) {
strncpy(name, c.name, 20);
hobby = new char[strlen(c.hobby) + 1];
strcpy(hobby, c.hobby);
weight = c.weight;
}
// 析构函数,delete[]
// 最后将hobby置为空指针很重要
Cow::~Cow() {
delete[] hobby;
hobby = nullptr;
}
Cow& Cow::operator=(const Cow& c) {
strncpy(name, c.name, 20);
hobby = new char[strlen(c.hobby) + 1];
strcpy(hobby, c.hobby);
weight = c.weight;
return *this;
}
void Cow::ShowCow() const {
std::cout << "name: " << name
<< ", hobby: " << hobby << ", weight: " << weight;
}
// 12-1
#include
#include "cow.h"
int main() {
Cow cow1;
Cow cow2 = Cow("XiaoHua", "Run", 23.5);
Cow cow3 = Cow("XiaoHong", "Eat", 45.7);
Cow cow4 = cow2;
cow1 = cow3;
std::cout << "cow1: ";
cow1.ShowCow();
std::cout << "\ncow2: ";
cow2.ShowCow();
std::cout << "\ncow3: ";
cow3.ShowCow();
std::cout << "\ncow4: ";
cow4.ShowCow();
return 0;
}
2. 通过完成下面的工作来改进String类声明(即将String1.h升级String2.h)。
a. 对+运算符进行重载,使之可将两个字符串合并成1个。
b. 提供一个Stringlow()成员函数,将字符串中所有的字母字符转换为小写(别忘了cctype系列字符函数)。
c. 提供String()成员函数,将字符串中所有字母字符转换成大写。
d. 提供一个这样的成员函数,它接受一个char参数,返回该字符在字符串中出现的次数。
使用下面的程序测试:
// pe12-2
#include
using namespace std;
#include "string2.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 of 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;
}
解答:
#pragma once
// string2.h
#ifndef STRING2_H_
#define STRING2_H_
#include
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& s); // 复制构造函数
~String();
int length() const { return len; }
String& Stringlow();
String& Stringup();
int has(char c); // 返回c在字符串中出现的次数
// 重载运算符
String& operator=(const String& s);
String& operator=(const char* s);
char& operator[](int i);
const char& operator[](int i) const;
// 友元函数
friend bool operator<(const String& s1, const String& s2);
friend bool operator>(const String& s1, const String& s2);
friend bool operator==(const String& s1, const String& s2);
friend ostream& operator<<(ostream& os, const String& s);
friend istream& operator>>(istream& is, String& s);
friend String operator+(const String& s1, const String& s2);
friend String operator+(const String&, const char*);
friend String operator+(const char*, const String&);
// 静态函数
static int HowMany();
};
#endif // !STRING2_H_
// string2.cpp
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include "string2.h"
using std::strlen;
using std::strcpy;
using std::strcat;
using std::strcmp;
using std::ostream;
using std::istream;
// 初始化static类成员 !!!
int String::num_strings = 0;
int String::HowMany() {
return num_strings;
}
String::String(const char* s) {
len = strlen(s);
str = new char[len + 1];
strcpy(str, s);
num_strings++;
}
String::String() {
str = nullptr;
len = 0;
num_strings++;
}
String::String(const String& s) {
len = s.len;
str = new char[len + 1];
strcpy(str, s.str);
num_strings++;
}
String::~String() {
delete[] str;
str = nullptr;
len = 0;
num_strings--;
}
String& String::Stringlow() {
if (len == 0) return *this;
for (int i = 0; i < len; i++) {
str[i] = std::tolower(str[i]);
}
return *this;
}
String& String::Stringup() {
if (len == 0) return *this;
for (int i = 0; i < len; i++)
str[i] = std::toupper(str[i]);
return *this;
}
int String::has(char c) {
if (len == 0) return 0;
int res = 0;
for (int i = 0; i < len; i++) {
if (str[i] == c)
res++;
}
return res;
}
String& String::operator=(const String& s) {
// 首先防止自己赋给自己
if (this == &s) return *this;
len = s.len;
delete[] str;
str = new char[len + 1];
strcpy(str, s.str);
return *this;
}
String& String::operator=(const char* s) {
len = strlen(s);
delete[] str;
str = new char[len + 1];
strcpy(str, s);
return *this;
}
// 主要为修改
char& String::operator[](int i) {
// if(len == 0)
// if (i >= len) return str[len - 1];
return str[i];
}
const char& String::operator[](int i) const {
return str[i];
}
bool operator<(const String& s1, const String& s2) {
return strcmp(s1.str, s2.str) < 0;
}
bool operator>(const String& s1, const String& s2) {
return strcmp(s1.str, s2.str) > 0;
}
bool operator==(const String& s1, const String& s2) {
return strcmp(s1.str, s2.str) == 0;
}
ostream& operator<<(ostream& os, const String& s) {
os << s.str;
return os;
}
// !!!
istream& operator>>(istream& is, String& s) {
char temp[String::CINLIM];
is.get(temp, String::CINLIM);
if (is)
s = temp;
while (is && is.get() != '\n')
continue;
return is;
}
String operator+(const String& s1, const String& s2) {
int len = s1.len + s2.len;
char* str = new char[len + 1];
strcpy(str, s1.str);
// strcpy(temp + s1.len, st.str);
strcat(str, s2.str);
return String(str);
}
String operator+(const String& s1, const char* s2) {
int len = s1.len + strlen(s2);
char* str = new char[len + 1];
strcpy(str, s1.str);
strcpy(str + s1.len, s2);
return String(str);
}
String operator+(const char* s1, const String& s2) {
return String(s1)+s2;
}
// pe12-2
#include
using namespace std;
#include "string2.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 of 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测试新的定义程序。
#pragma once
#ifndef STOCK20_H_
#define STOCK20_H_
#include
class Stock {
private:
char* company;
int shares;
double share_val;
double total_val;
void set_tot() { total_val = share_val * shares; }
public:
Stock();
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);
const Stock& topval(const Stock& s) const;
friend std::ostream& operator<<(std::ostream& os, const Stock& st);
};
#endif // !STOCK20_H_
// stock20.cpp
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include "stock20.h"
using std::strlen;
using std::strcpy;
using std::cout;
Stock::Stock() {
company = nullptr;
shares = 0;
share_val = total_val = 0.0;
}
Stock::Stock(const char* co, long n, double pr) {
int len = strlen(co);
company = new char[len + 1];
strcpy(company, co);
if (n < 0)
cout << "Number of shares can't be negative; "
<< company << " shares set to 0.\n";
else
shares = n;
share_val = pr;
set_tot();
}
Stock::~Stock() {
delete[] company;
}
void Stock::buy(long num, double price) {
if (num < 0)
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 purchased 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();
}
const Stock& Stock::topval(const Stock& s) const {
if (s.total_val > total_val)
return s;
else
return *this;
}
std::ostream& operator<<(std::ostream& os, const Stock& st) {
using std::ios_base;
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;
os.precision(2);
os << " Total Worth: $" << st.total_val << '\n';
os.setf(orig, ios_base::floatfield);
os.precision(prec);
return os;
}
// 12-3
#include
#include "stock20.h"
using std::cout;
const int STKS = 4;
int main(){
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];
}
const Stock* top = &stocks[0];
for (st = 0; st < STKS; st++)
{
top = &(top->topval(stocks[st]));
}
std::cout << "\nMost valuable holding:\n";
cout << *top;
return 0;
}
4. 请看下面程序定义的Stack类变量:
class Stack {
private:
enum { MAX = 10 };
Item* pitems; // hold stack items
int size;
int top;
public:
Stack(int n = MAX);
Stack(const Stack& st); // 复制构造函数
~Stack();
bool isempty() const;
bool isfull() const;
bool push(const Item& item);
bool pop(Item& item);
Stack& operator=(const Stack& st);};
正如私有成员表明的,这个类使用动态分配的数组来保存栈项。请重新编写方法,以适应这种新的表示法,并编写一个程序来演示所有的方法,包括复制构造函数和赋值运算符。
#pragma once
#ifndef STACK2_H_
#define STACK2_H_
typedef unsigned long Item;
class Stack {
private:
enum { MAX = 10 };
Item* pitems; // hold stack items
int size;
int top;
public:
Stack(int n = MAX);
Stack(const Stack& st); // 复制构造函数
~Stack();
bool isempty() const;
bool isfull() const;
bool push(const Item& item);
bool pop(Item& item);
Stack& operator=(const Stack& st);
};
#endif // !STACK2_H_
#include
#include "stack2.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];
top = st.top;
for (int i = 0; i < top; i++) {
pitems[i] = st.pitems[i];
}
}
Stack::~Stack() {
delete[] pitems;
pitems = nullptr;
}
bool Stack::isempty() const {
return top == 0;
}
bool Stack::isfull() const {
return top == size;
}
bool Stack::push(const Item& item) {
if (isfull())
return false;
pitems[top++] = item;
return true;
}
bool Stack::pop(Item& item) {
if (isempty())
return false;
item = pitems[--top];
return true;
}
Stack& Stack::operator=(const Stack& st) {
if (this == &st) return *this;
size = st.size;
delete[] pitems;
pitems = new Item[size];
top = st.top;
for (int i = 0; i < top; i++)
pitems[i] = st.pitems[i];
return *this;
}
#include
#include "stack2.h"
using std::cout;
using std::endl;
int main() {
Stack st1(10);
srand(time(0));
for (size_t i = 0; i < 10; i++) {
if (!st1.push(rand() % 100))
cout << "Push error!" << endl;
}
if (!st1.push(0))
cout << "Push 0 error!" << endl;
Stack st2(st1);
Stack st3 = st1;
for (size_t i = 0; i < 11; i++) {
Item item;
cout << "#" << i + 1 << ": " << endl;
if (!st1.pop(item))
cout << "st1 pop error!" << endl;
else
cout << "st1: " << item << endl;
if (!st2.pop(item))
cout << "st2 pop error!" << endl;
else
cout << "st2: " << item << endl;
if (!st3.pop(item))
cout << "st3 pop error!" << endl;
else
cout << "st3: " << item << endl;
cout << endl;
}
}
5. Heather银行进行的研究表明,ATM客户不希望排队时间超过1分钟。使用程序清单12.10中的模拟,找出要使平均等候时间为1分钟,每小时到达的客户数应为多少(试验时间不短于100小时)?
#pragma once
// queue.h -- 12.10 -- interface for a queue
#ifndef QUEUE_H
#define QUEUE_H
class Customer {
private:
long arrive;
int processtime;
public:
Customer() { arrive = processtime = 0; }
void set(long when);
long when() const { return arrive; }
int ptime() const { return processtime; }
};
typedef Customer Item;
class Queue {
private:
struct Node {
Item item;
struct Node* next;
};
enum { Q_SIZE = 10 };
Node* front; // 指向链表头
Node* rear; // 指向链表尾
int items; // 目前链表里的成员数量
const int qsize; // 链表里Item的最大数量
Queue(const Queue& q): qsize(0){}
Queue& operator=(const Queue& q) { return *this; }
public:
Queue(int qs = Q_SIZE);
~Queue();
bool isempty() const;
bool isfull() const;
int queuecount() const;
bool enqueue(const Item& item); // 结尾加节点
bool dequeue(Item& item); // 链表头删节点
};
#endif // !QUEUE_H
// queue.cpp
#include
#include "queue.h"
Queue::Queue(int qs) : qsize(qs) {
front = rear = nullptr;
items = 0;
}
Queue::~Queue() {
Node* temp;
while (front != nullptr) {
temp = front;
front = front->next;
delete temp;
}
}
bool Queue::isempty() const {
return items == 0;
}
bool Queue::isfull() const {
return items == qsize;
}
int Queue::queuecount() const {
return items;
}
bool Queue::enqueue(const Item& item) {
if (isfull()) return false;
Node* add = new Node;
// on failure, new throws std::bad_alloc exception
add->item = item;
add->next = nullptr;
items++;
if (front == nullptr)
front = add;
else
rear->next = add;
rear = add;
return true;
}
bool Queue::dequeue(Item& item) {
if (front == nullptr)
return false;
item = front->item;
items--;
Node* temp = front;
front = front->next;
delete temp;
if (items == 0)
rear = nullptr;
return true;
}
// time set to a random value in the range 1-3
void Customer::set(long when) {
processtime = std::rand() % 3 + 1;
arrive = when;
}
// 12-5
#include
#include // rand(), srand(), RAND_MAX
#include // time()
#include "queue.h"
const int MIN_PER_HR = 60;
bool newcustomer(double x); // 判断是否有新用户到来
int main() {
using std::cin;
using std::cout;
using std::endl;
using std::ios_base;
std::srand(std::time(0)); // 随机初始化rand()
cout << "Case Study: Bank of Heather Automatic Teller\n";
cout << "Enter maximum size of queue: ";
int qs;
cin >> qs;
Queue line(qs);
cout << "Enter the number of simulation hours (no less than 100): ";
int hours;
cin >> hours;
// 循环每1分钟运行一次
long cyclelimit = MIN_PER_HR * hours;
//cout << "Enter the average number of customers per hour: ";
//double perhour;
//cin >> perhour;
//double min_per_cust;
//min_per_cust = MIN_PER_HR / perhour;
Item temp;
long turnaways = 0; // 因满队列而拒绝接收的人数
long customers = 0; // 加入队列的数量
long served = 0; // 仿真期间服务的人数
long sum_line = 0; // 累计队列长度
int wait_time = 0; // 自动存取机的空闲时间
long line_wait = 0; // 累计在队列中的时间
double avg_wait_time = 0.0; // 顾客平均等待时间
// 每小时使用人数初始值设为15,之后进行+1枚举测试
double perhour = 15;
double min_per_cust;
// 仿真开始
do {
min_per_cust = MIN_PER_HR / perhour;
turnaways = 0; // 因满队列而拒绝接收的人数
customers = 0; // 加入队列的数量
served = 0; // 仿真期间服务的人数
sum_line = 0; // 累计队列长度
wait_time = 0; // 自动存取机的空闲时间
line_wait = 0; // 累计在队列中的时间
avg_wait_time = 0.0; // 顾客平均等待时间
// 清空队列
while (!line.isempty())
line.dequeue(temp);
for (int cycle = 0; cycle < cyclelimit; cycle++) {
if (newcustomer(min_per_cust)) // 有新顾客到来
{
if (line.isfull())
turnaways++;
else {
customers++;
temp.set(cycle); // cycle = time of arrival
line.enqueue(temp);
}
}
if (wait_time <= 0 && !line.isempty()) {
line.dequeue(temp); // 下一个客户
wait_time = temp.ptime();
line_wait += cycle - temp.when();
served++;
}
if (wait_time > 0)
wait_time--;
sum_line += line.queuecount();
}
// 报告结果
if (customers > 0) {
cout << "custormers accepted: " << customers << endl;
cout << " customers served: " << served << endl;
cout << " turnaways: " << turnaways << endl;
cout << " average queue size: ";
cout.precision(2);
cout.setf(ios_base::fixed, ios_base::floatfield);
cout << double(sum_line / cyclelimit) << endl;
avg_wait_time = double(line_wait / served);
cout << " average wait time: " << avg_wait_time << " minutes\n";
}
else
cout << "No customers!\n";
} while ((perhour++) && ((avg_wait_time < 0.9) || (avg_wait_time > 1.1)));
cout << "When perhour = " << perhour << ", the average wait time will be about 1 minute.\n";
cout << "Done!\n";
return 0;
}
bool newcustomer(double x) {
return (std::rand() * x / RAND_MAX < 1);
}
6. Heather银行想知道,如果再开设一台ATM,情况将如何。请对模拟进行修改,以包含两个队列。假设当第一台ATM前的排队人数少于第二台ATM时,客户将排在第一队,否则排在第二队。然后再找出要使平均等候时间为1分钟,每小时到达的客户数应该为多少(注意,这是一个非线性问题,即将ATM数量加倍,并不能保证每小时处理的客户数量也加倍,并确保客户等候的时间少于1分钟)?
// 12-6
#include
#include // rand(), srand(), RAND_MAX
#include // time()
#include "queue.h"
const int MIN_PER_HR = 60;
bool newcustomer(double x); // 判断是否有新用户到来
int main() {
using std::cin;
using std::cout;
using std::endl;
using std::ios_base;
std::srand(std::time(0)); // 随机初始化rand()
cout << "Case Study: Bank of Heather Automatic Teller\n";
cout << "Enter maximum size of queue: ";
int qs;
cin >> qs;
Queue line1(qs);
Queue line2(qs);
cout << "Enter the number of simulation hours (no less than 100): ";
int hours;
cin >> hours;
// 循环每1分钟运行一次
long cyclelimit = MIN_PER_HR * hours;
//cout << "Enter the average number of customers per hour: ";
//double perhour;
//cin >> perhour;
//double min_per_cust;
//min_per_cust = MIN_PER_HR / perhour;
Item temp;
long turnaways = 0; // 因满队列而拒绝接收的人数
long customers = 0; // 加入队列的数量
long served = 0; // 仿真期间服务的人数
long sum_line = 0; // 累计队列长度
int wait_time1 = 0; // 自动存取机1的空闲时间
int wait_time2 = 0; // 自动存取机2的空闲时间
int line1_size = 0; // 队列1当前长度
int line2_size = 0; // 队列2当前长度
long line_wait = 0; // 累计在队列中的时间
double avg_wait_time = 0.0; // 顾客平均等待时间
// 每小时使用人数初始值设为15,之后进行+1枚举测试
double perhour = 15;
double min_per_cust;
// 仿真开始
do {
min_per_cust = MIN_PER_HR / perhour;
turnaways = 0; // 因满队列而拒绝接收的人数
customers = 0; // 加入队列的数量
served = 0; // 仿真期间服务的人数
sum_line = 0; // 累计队列长度
wait_time1 = 0; // 自动存取机1的空闲时间
wait_time2 = 0;
line1_size = 0;
line2_size = 0;
line_wait = 0; // 累计在队列中的时间
avg_wait_time = 0.0; // 顾客平均等待时间
// 清空队列
while (!line1.isempty())
line1.dequeue(temp);
while (!line2.isempty())
line2.dequeue(temp);
for (int cycle = 0; cycle < cyclelimit; cycle++) {
if (newcustomer(min_per_cust)) // 有新顾客到来
{
if (line1.isfull() && line2.isfull())
turnaways++;
else if(line1_size > line2_size){
customers++;
temp.set(cycle); // cycle = time of arrival
line2.enqueue(temp);
line2_size++;
}
else {
customers++;
temp.set(cycle);
line1.enqueue(temp);
line1_size++;
}
}
if (wait_time1 <= 0 && !line1.isempty()) {
line1.dequeue(temp); // 下一个客户
line1_size--;
wait_time1 = temp.ptime();
line_wait += cycle - temp.when();
served++;
}
if (wait_time2 <= 0 && !line2.isempty()) {
line2.dequeue(temp); // 下一个客户
line2_size--;
wait_time2 = temp.ptime();
line_wait += cycle - temp.when();
served++;
}
if (wait_time1 > 0)
wait_time1--;
if (wait_time2 > 0)
wait_time2--;
sum_line += line1.queuecount();
sum_line += line2.queuecount();
}
// 报告结果
if (customers > 0) {
cout << "custormers accepted: " << customers << endl;
cout << " customers served: " << served << endl;
cout << " turnaways: " << turnaways << endl;
cout << " average queue size: ";
cout.precision(2);
cout.setf(ios_base::fixed, ios_base::floatfield);
cout << double(sum_line / cyclelimit) << endl;
avg_wait_time = double(line_wait / served);
cout << " average wait time: " << avg_wait_time << " minutes\n";
}
else
cout << "No customers!\n";
} while ((perhour++) && ((avg_wait_time < 0.9) || (avg_wait_time > 1.1)));
cout << "When perhour = " << perhour << ", the average wait time will be about 1 minute.\n";
cout << "Done!\n";
return 0;
}
bool newcustomer(double x) {
return (std::rand() * x / RAND_MAX < 1);
}