习题选自:C++ Primer Plus(第六版)
内容仅供参考,如有错误,欢迎指正 !
- 构造函数是一种特殊的类成员函数,在创建类对象时被调用。
- 构造函数的名称和类名相同,但通过函数重载,可创建多个同名的构造函数,条件是每个函数的特征标(参数列表)不同。
- 每个成员函数(包括构造函数和析构函数)都有一个this指针,this指针指向调用对象,如果方法需要引用整个调用对象,则可以使用表达式*this。在函数的括号后面使用限定符将this限定为const,这样将不能使用this来修改对象的值。
复习题
1.什么是类?
类是用户定义的类型的定义。类声明指定了数据将如何存储,同时提供了访问和操作这些数据的方法。
2.类如何实现抽象、封装和数据隐藏?
用户可以根据类的公有接口对类对象执行的操作,这是抽象。类的数据成员可以是私有的(默认值),这意味着只能通过类成员函数来对数据进行访问,这是数据隐藏。实现的具体细节(如数据的表示和方法的代码)都是隐藏的,这是封装。
3.对象和类之间的关系是什么?
类定义了一种类型,包括如何使用它。对象是一个变量或其他的数据对象(如new生成的),并根据类定义被创建和使用。类和对象之间的关系同标准类型与其变量之间的关系。
4.除了是函数之外,类函数成员与类数据成员之间的区别是什么?
如果创建给定类的多个对象,则每个对象都有其自己的数据内存空间;但所有的对象都使用同一组成员函数(通常,这个方法是公有的,而数据是私有的,但这只是策略方面的问题,而不是对类的要求)
5.定义一个类来表示银行账户、数据成员包括储户姓名、帐号(使用字符串)和存款。成员函数执行如下操作:
- 创建一个对象并将其初始化。
- 显示储户姓名、帐号和存款。
- 存入参数指定的存款。
- 取出参数指定的款项。
请提供类声明,而不用给出方法实现。(编程练习1将要求编写实现)
#ifndef BANKACCOUNT_H
#define BANKACCOUNT_H
#include <string>
using namespace std;
class BankAccount
{
private:
std::string name_str;
std::string accountNum_str;
double balance;
public:
BankAccount(const string &name, const string &accountNum, double bal = 0.0);
void show();
void deposit(double cash);
void withdraw(double cash);
};
#endif
6.类构造函数在何时被调用?类析构函数呢?
在创建类对象或显示调用构造函数时,类的构造函数被调用。当函数过期时,析构函数被调用。
7.给出复习题5中的银行账户的构造函数的代码。
#include "BankAccount.h"
#include <iostream>
using namespace std;
BankAccount::BankAccount(const string &name, const string &accountNum, double bal)
{
name_str = name;
accountNum_str = accountNum;
balance = bal;
}
void BankAccount::show()
{
cout << "Account Name : " << name_str << endl;
cout << "Account Number : " << accountNum_str << endl;
cout << "Account Balance : " << balance << endl;
}
void BankAccount::withdraw(double cash)
{
balance -= cash;
}
void BankAccount::deposit(double cash)
{
balance += cash;
}
8.什么是默认构造函数,拥有默认构造函数有何好处?
默认构造函数是没有参数或所有参数都有默认值的构造函数。拥有默认构造函数后,可以声明对象,而不初始化它,即使已经定义了初始化构造函数。它还使得能够声明数组。
9.修改Stock类的定义(stock20.h中的版本),使之包含返回各个数据成员值的成员函数。注意:返回公司名的成员函数不应该为修改数组提供便利,也就是说,不能简单的返回string引用。
原stock20.h的版本:
//Listing 10.7 stock20.h // stock20.h -- augmented version #ifndef STOCK20_H_ #define STOCK20_H_ #include <string> class Stock { private: std::string company; int shares; double share_val; double total_val; void set_tot() { total_val = shares * share_val; } public: Stock(); // default constructor Stock(const std::string &co, long n = 0, double pr = 0.0); ~Stock(); // do-nothing destructor void buy(long num, double price); void sell(long num, double price); void update(double price); void show() const; const Stock &topval(const Stock &s) const; }; #endif
修改后:
#ifndef STOCK20_H_
#define STOCK20_H_
#include <string>
class Stock
{
private:
std::string company;
int shares;
double share_val;
double total_val;
void set_tot() { total_val = shares * share_val; }
public:
Stock();
Stock(const std::string &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);
void show() const;
const Stock &topval(const Stock &s) const;
int shares() const { return shares; }
double shareVal() const { return share_val; }
double totalVal() const { return total_val; }
const std::string &comp_name() const { return company; }
};
#endif
10.this和*this是什么?
this指针是类方法可以使用的指针,它指向用于调用方法的对象。因此,this是对象的地址,*this是对象本身。
编程练习
1.为复习题5描述的类提供方法定义,并编写一个小程序来演示所有的特性。
BankAccount.h:
#ifndef BANKACCOUNT_H
#define BANKACCOUNT_H
#include <string>
using namespace std;
class BankAccount
{
private:
std::string name_str;
std::string accountNum_str;
double balance;
public:
BankAccount(const string &name, const string &accountNum, double bal = 0.0);
void show();
void deposit(double cash);
void withdraw(double cash);
};
#endif
BankAccount.cpp:
#include "BankAccount.h"
#include <iostream>
using namespace std;
BankAccount::BankAccount(const string &name, const string &accountNum, double bal)
{
name_str = name;
accountNum_str = accountNum;
balance = bal;
}
void BankAccount::show()
{
cout << "Account Name : " << name_str << endl;
cout << "Account Number : " << accountNum_str << endl;
cout << "Account Balance : " << balance << endl;
}
void BankAccount::withdraw(double cash)
{
balance -= cash;
}
void BankAccount::deposit(double cash)
{
balance += cash;
}
main.cpp:
#include "BankAccount.h"
#include <iostream>
using namespace std;
int main()
{
string name, account;
double num;
cout << "enter name : ";
getline(cin, name);
cout << "enter bank account : ";
getline(cin, account);
BankAccount ba(name, account);
cout << "enter the deposit amount : ";
cin >> num;
cin.get();
ba.deposit(num);
cout << "your current bank account information : ";
ba.show();
cout << "enter the withdrawal amount: ";
cin >> num;
cin.get();
ba.withdraw(num);
cout << "your current bank account information : ";
ba.show();
return 0;
}
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
Person.h :
#ifndef PERSON_H
#define PERSON_H
#include <string>
using std::string;
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
};
#endif
Person.cpp :
#include "Person.h"
#include <iostream>
using std::cout;
using std::endl;
Person::Person(const string &ln, const char *fn)
{
lname = ln;
strcpy(fname, fn);
}
void Person::FormalShow() const
{
cout << fname << " " << lname << endl;
}
void Person::Show() const
{
cout << fname << " , " << lname << endl;
}
main.cpp :
#include "Person.h"
#include <iostream>
using std::cout;
using std::endl;
int main()
{
Person one;
Person two("Smythecraft");
Person three("Dimwiddy", "Sam");
cout << "Person one : " << endl;
one.Show();
one.FormalShow();
cout << "Person two : " << endl;
two.Show();
two.FormalShow();
cout << "Person two : " << endl;
three.Show();
three.FormalShow();
return 0;
}
3.完成第9章的编程练习1,但要用正确的golf类声明替换那里的代码。用带合适参数的构造函数替换setgolf(golf &, const char * , int),以提供初始值。保留setgolf()的交互版本,但要用构造函数来实现它(例如,setgolf()的代码应该获得数据,将数据传递给构造函数来创建一个临时对象,并将其赋给调用对象,即*this)。
Golf.h:
#ifndef GOLF_H
#define GOLF_H
class Golf
{
public:
Golf();
Golf(const char *name, int hc);
int setgolf();
void sethandicap(int hc);
void showgolf() const;
private:
static const int Len = 40;
char fullname[Len];
int handicap;
};
#endif
Golf.cpp:
#include "Golf.h"
#include <iostream>
using namespace std;
Golf::Golf()
{
strcpy(fullname, "DefaultName");
handicap = 0;
}
Golf::Golf(const char *name, int hc)
{
strcpy(fullname, name);
handicap = hc;
}
int Golf::setgolf()
{
cout << "please enter fullname : ";
cin.getline(fullname, Len);
if (strlen(fullname) == 0)
return 0;
else
{
cout << "please enter handicap : ";
cin >> handicap;
cin.get();
return 1;
}
}
void Golf::sethandicap(int hc)
{
handicap = hc;
}
void Golf::showgolf() const
{
cout << "fullname : " << fullname << ", handicap : " << handicap << endl;
}
main.cpp:
#include "Golf.h"
#include <iostream>
using namespace std;
int main()
{
Golf ann("Ann Birdfree", 24), andy, arrGolf[3];
ann.showgolf();
andy.showgolf();
andy.setgolf();
andy.showgolf();
andy.sethandicap(20);
andy.showgolf();
int i = 0;
while (i < 3 && arrGolf[i].setgolf())
{
arrGolf[i].showgolf();
i++;
if (i < 3)
cout << "next one: " << endl;
}
return 0;
}
4.完成第9章的编程练习4,但将Sales结构及相关的函数转换为一个类及其方法。用构造函数替换setSales(sales &, double [], int)函数。用构造函数实现setSales(Slaes &)方法的交互版本。将类保留在名称空间SALES 中。
sales.h:
//sales.h-----头文件
#ifndef SALES_H
#define SALES_H
namespace SALES
{
const int QUARTERS = 4;
class Sales
{
public:
Sales();
Sales(const double ar[], int n);
void showSales();
private:
double sales[QUARTERS];
double average;
double max;
double min;
};
}
#endif
sales.cpp:
//sales.cpp-----源代码文件
#include "sales.h"
#include <iostream>
using namespace std;
namespace SALES
{
Sales::Sales(const double ar[], int n)
{
double min = 0, max = 0, sum = 0;
min = max = ar[0];
for (int i = 0; i < n; i++)
{
sales[i] = ar[i];
sum += ar[i];
if (ar[i] > max)
{
max = ar[i];
}
if (ar[i] < min)
{
min = ar[i];
}
}
average = sum / n;
}
Sales::Sales()
{
cout << "Please enter 4 quarters for sales:" << endl;
cout << "the 1 quarter :";
cin >> sales[0];
min = max = sales[0];
for (int i = 1; i < 4; i++)
{
cout << "the " << i << " quarter :";
cin >> sales[i];
if (max < sales[i])
{
max = sales[i];
}
if (min > sales[i])
{
min = sales[i];
}
}
average = (sales[0] + sales[1] + sales[2] + sales[3]) / 4;
}
void Sales::showSales()
{
cout << "Display all information in sales : " << endl;
cout << "The 4 quarters are $" << sales[0] << ", $" << sales[1] << ", $" << sales[2] << ", $" << sales[3] << endl;
cout << "The average income is $" << average << endl;
cout << "The maximum income is $" << max << endl;
cout << "The minimum income is $" << min << endl;
}
}
main.cpp:
#include "sales.h"
#include <iostream>
using namespace SALES;
int main()
{
double arr[4] = {3.4, 5.6, 2.5, 6.1};
Sales s1(arr, 4);
s1.showSales();
Sales s2;
s2.showSales();
return 0;
}
5.考虑下面的结构声明:
struct customer { char fullname[35]; double payment; };
编写一个程序,它从栈中添加和删除customer结构(栈用Stack类声明表示)。每次customer结构被删除时,其payment的值都被加入到总数中,并报告总数。注意:应该可以直接使用Stack类而不作修改;只需修改typedef声明,使Item的类型为customer,而不是unsigned long即可.
stack.h :
#ifndef STACK_H
#define STACK_H
struct customer
{
char fullname[35];
double payment;
};
typedef customer Item;
class Stack
{
public:
Stack();
bool pop(Item &it);
bool push(const Item &it);
bool isfull() const;
bool isempty() const;
private:
double total;
int top;
enum
{
MAX = 10
};
Item item[MAX];
};
#endif
stack.cpp :
#include "stack.h"
#include <iostream>
using namespace std;
Stack::Stack()
{
top = 0;
total = 0;
}
bool Stack::isempty() const
{
return top == 0;
}
bool Stack::isfull() const
{
return top == MAX;
}
bool Stack::pop(Item &it)
{
if (top > 0)
{
it = item[--top];
total += it.payment;
cout << "An order has been processed, current total revenue : " << total << endl;
return true;
}
else
{
return false;
}
}
bool Stack::push(const Item &it)
{
if (top < MAX)
{
item[top++] = it;
return true;
}
else
{
return false;
}
}
main.cpp :
#include "stack.h"
#include <iostream>
using namespace std;
int main()
{
Stack stack;
customer cu;
char ch;
cout << "Press a to add a customer, P to process an order, and Q to exit." << endl;
while (cin >> ch && toupper(ch) != 'Q')
{
while (cin.get() != '\n')
{
continue;
}
if (!isalpha(ch))
{
cout << '\a';
continue;
}
switch (ch)
{
case 'a':
case 'A':
if (stack.isfull())
{
cout << "The order of 10 customers has been filled. Please process the existing order first !" << endl;
}
else
{
cout << "Add customer name : ";
cin.getline(cu.fullname, 35);
cout << "Add the customer's consumption amount : ";
cin >> cu.payment;
cout << "dsssd : " << stack.push(cu);
}
break;
case 'p':
case 'P':
if (stack.isempty())
{
cout << " There are currently no unprocessed orders." << endl;
}
else
{
stack.pop(cu);
}
break;
default:
cout << " Input error!!!" << endl;
break;
}
cout << "Press a to add a customer, P to process an order, and Q to exit." << 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 reset(double a = 0, double b = 0); // resets x,y to a, b }
请提供成员函数的定义和测试这个类的程序。
move.h :
#ifndef MOVE_H
#define MOVE_H
class Move
{
private:
double x;
double y;
public:
Move(double a = 0, double b = 0); //sets x, y to a, b
void 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
void reset(double a = 0, double b = 0); // resets x,y to a, b
};
#endif
move.cpp :
#include "move.h"
#include <iostream>
Move::Move(double a, double b)
{
x = a;
y = b;
}
Move Move::add(const Move &m) const
{
return Move(x + m.x, y + m.y);
}
void Move::showmove() const
{
std::cout << "x is :" << x << std::endl;
std::cout << "y is :" << y << std::endl;
}
void Move::reset(double a, double b)
{
x = a;
y = b;
}
main.cpp :
#include "move.h"
#include <iostream>
int main()
{
Move m1(1, 2), m2(3, 4);
m1.showmove();
m2.showmove();
m1.add(m2).showmove();
m1.reset(5, 6);
m1.showmove();
return 0;
}
7.Betelgeusean plorg有这些特征.
数据:
- plorg的名称不超过19个字符;
- plorg有满意指数(CI),这是一个整数。
操作:
- 新的plorg将有名称,其CI值为50;
- plorg的CI可以修改;
- plorg可以报告其名称和CI;
- plorg的默认名称为“Plorga”。
请编写一个Plorg类声明(包括数据成员和成员函数原型)来表示plorg,并编写成员函数的函数定义。然后编写一个小程序,以演示Plorg类的所有特性。
plorg.h :
#ifndef PLORG_H
#define PLORG_H
class Plorg
{
private:
char name[19];
int CI;
public:
Plorg();
Plorg( const char *n, int ci);
void show();
void setCI(int ci);
};
#endif
plorg.cpp :
#include "plorg.h"
#include <iostream>
Plorg::Plorg()
{
strcpy(name, "Plorg");
CI = 0;
}
Plorg::Plorg(const char *n, int ci)
{
strcpy(name, n);
CI = ci;
}
void Plorg::setCI(int ci)
{
CI = ci;
}
void Plorg::show()
{
std::cout << "name : " << name << ", CI: " << CI << std::endl;
}
main.cpp :
#include "plorg.h"
#include <iostream>
int main()
{
Plorg p1, p2("plorg2", 50);
p1.show();
p2.show();
p1.setCI(30);
p1.show();
}
8.可以将简单列表描述成下面这样:
-
可存储0或多个类型的列表;
-
可创建空列表
-
可在列表中添加数据项;
-
可确定列表是否为空;
-
可确定列表是否已满;
-
可访问列表中每一个数据项,并对它执行某种操作。
可以看到,这个列表确实很简单,例如它不允许插入或删除数据项。
请设计一个List类来表示这中数据类型。您应提供头文件list.h和实现文件list.cpp.前者包含定义,后者包含实现这个类的方法。您还应创建一个简短的程序来实现这个类。
该表的规范很简单,这主要旨在简化这个编程练习,可以选择使用数组或链表来实现这个列表,但公有结构不应依赖与说做的选择。也就是说,公有接口不应有数组索引,节点指针等。应使用通用概念来表达创建列表、在列表中添加数据项等操作。对于访问数据项以及执行操作,通常应使用将函数指针做为参数的函数来处理:
void visit(void (*pf) (Item&));
其中,pf指向一个将Item引用作为参数的函数(不是成员函数),Item是列表中数据项的类型,visit()函数将该函数用于列表中的每个数据项。
list.h :
#ifndef LIST_H
#define LIST_H
typedef int Item;
const int MAX = 10;
class List
{
private:
Item ITEM[MAX];
int COUNT;
public:
List();
bool isfull();
bool isempty();
bool addItem(Item it);
Item *item();
int count();
void visit(void (*pf)(Item &));
};
#endif
list.cpp :
#include "list.h"
#include <iostream>
List::List()
{
COUNT = 0;
}
bool List::isfull()
{
return COUNT == MAX;
}
bool List::isempty()
{
return COUNT == 0;
}
bool List::addItem(Item it)
{
if (this->isfull())
{
std::cout << "full already, add fail. " << std::endl;
return false;
}
else
{
ITEM[COUNT++] = it;
return true;
}
}
Item *List::item()
{
return ITEM;
}
int List::count()
{
return COUNT;
}
void List::visit(void (*pf)(Item &))
{
for (int i = 0; i < COUNT; i++)
{
(*pf)(ITEM[i]);
}
}
main.cpp :
#include "list.h"
#include <iostream>
void intadd2(int &n);
int main()
{
List l;
l.addItem(1);
l.addItem(2);
l.addItem(3);
for (int i = 0; i < 3; i++)
{
std::cout << l.item()[i] << std::endl;
}
l.visit(intadd2);
for (int i = 0; i < 3; i++)
{
std::cout << l.item()[i] << std::endl;
}
return 0;
}
void intadd2(int &n)
{
n += 2;
}
网友评论