C++ Primer Plus习题及答案

C++ Primer Plus习题及答案-第十章

2022-10-07  本文已影响0人  艰默

习题选自: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类声明(包括数据成员和成员函数原型)来表示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.可以将简单列表描述成下面这样:
可以看到,这个列表确实很简单,例如它不允许插入或删除数据项。
请设计一个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;
}
上一篇下一篇

猜你喜欢

热点阅读