C++ primer plus 阅读记录-类和动态内存分配

来源:互联网 发布:java写入日志文件 编辑:程序博客网 时间:2024/05/21 16:56

1. 静态类成员
private:
static int num_strings;

无论创建了多少对象,程序都只创建一个静态类变量副本。也就是说,类的所有对象共享同一个静态成员。

// initializing static class member
int StringBad::num_strings = 0; //没有使用关键字static

注意:静态数据成员在类声明中声明,在包含类方法的文件中初始化。初始化时使用作用域运算符来指出静态成员所属的类。但如果静态成员是整型或枚举型const,则可以在类声明中初始化。

2. 在构造函数中使用new来分配内存时,必须在相应的析构函数中使用delete来释放内存。如果使用new[]来分配内存,则应使用delete[]来释放内存。

3. 特殊成员函数
C++自动提供了下面这些成员函数:
默认构造函数,如果没有定义构造函数;
默认析构函数,如果没有定义;
复制构造函数,如果没有定义;//StringBad(const StringBad &);
赋值运算符,如果没有定义;
地址运算符,如果没有定义;

复制构造函数用于将一个对象复制到新创建的对象中,它用于初始化过程中,也包括按值传递参数,而不是常规的赋值过程中。
这里写图片描述

默认的复制构造函数逐个复制非静态成员,复制的是成员的值。静态成员如num_strings不受影响,因为它属于整个类,而不是各个对象。

赋值运算符

StringBad & StringBad::operator=(const StringBad & st){    if(this == &st)        return *this;    delete [] str; //free old string    len = st.len;    str = new char[len+1];    std::strcpy(str,st.str);//深度复制    return *this;    //赋值操作不创建新的对象,因此不需要调整静态数据成员num_strings的值}

这里写图片描述

4. 静态类成员函数
static int HowMany() { return num_strings;}
其调用方式:
int count = String::HowMany();

首先,不能通过对象调用静态成员函数,如果静态成员函数是在公有部分声明的,则可以使用类名和作用域解析运算符来调用它。
其次,由于静态成员函数不与特定的对象相关联,因此只能使用静态数据成员。

5. 完善后的string1类代码

//string1.h#ifndef STRING1_H_#define STRING1_H_#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 &);    ~String();    int length() const {return len; }    //overloaded operator methods    String & operator=(const String &);    String & operator=(const char *);    char & operator[](int i);    const char & operator[](int i) const;    friend bool operator<(const String &st, const String &st2);    friend bool operator>(const String &st, const String &st2);    friend bool operator==(const String &st, const String &st2);    friend ostream & operator<<(ostream & os, const String& st);    friend istream & operator>>(istream & is, String& st);    //static function    static int HowMany();};#endif
//string1.cpp#include <cstring>#include "string1.h"using std::cin;using std::cout;int String::num_strings = 0;int String::HowMany() {return num_strings;}String::String(const char *s){    len = std::strlen(s);    str = new char[len+1];    std::strcpy(str,s);    num_strings++;}String::String(){    len = 0;    str = 0;    num_strings++;}String::String(const String& st){    len = st.len;    str = new char[len+1];    std::strcpy(str,st.str);    num_strings++;}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];    std::strcpy(str,st.str);    return *this;}String & String::operator=(const char* s){    delete [] str;    len = std::strlen(s);    str = new char[len+1];    std::strcpy(str,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) < 0);}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;}//quick and dirty String inputistream & 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;}
//程序清单12.6 saying1.cpp//compile with string1.cpp#include <iostream>#include "string1.h"const int ArSize = 10;const int MaxLen = 81;int main(){    using std::cout;    using std::cin;    using std::endl;    String name;    cout << "Hi, what's your name?\n>> ";    cin >> name;    cout << name << ", please enter up to " << ArSize <<" short sayings <empty line to quit>:\n";    String sayings[ArSize];    char temp[MaxLen];    int i;    for(i=0; i < ArSize; i++)    {        cout<<i+1 <<": ";        cin.get(temp, MaxLen);        while(cin && cin.get()!= '\n')            continue;        if(!cin || temp[0] == '\0')            break;        else            sayings[i] = temp;    }    int total = i;    if(total > 0)    {        cout << "Here are your sayings:\n";        for(i=0;i<total;i++)            cout << sayings[i][0] <<": "<<sayings[i] <<endl;        int shortest = 0;        int first = 0;        for(i =1; i < total;i++)        {            if(sayings[i].length() < sayings[shortest].length())                shortest = i;            if(sayings[i] < sayings[first])                first = i;        }        cout << "Shortest saying:\n" << sayings[shortest]<<endl;        cout << "First alphabetically:\n" << sayings[first]<< endl;        cout << "This program used " << String::HowMany() <<"String objects. Bye.\n";    }    else        cout << "No input! Bye. \n";    return 0;}

6. 返回对象
如果方法或函数要返回局部对象,则应返回对象,而不是指向对象的引用。在这种情况下,将使用复制构造函数来生成返回的对象。如果方法或函数要返回一个没有复制构造函数的类(如ostream)的对象,它必须返回一个指向这种对象的引用。有些方法和函数可以返回对象,也可以返回指向对象的引用,在这种情况下,应首选引用,因其效率更高。

7. 指向对象的指针
这里写图片描述

8. 队列模拟
队列Queue是一种抽象的数据类型,可以存储有序的项目序列,FIFO

链表由节点序列构成。每一个节点中都包含要保存到链表中的信息以及一个指向下一个节点的指针。

struct Node{    Item item;    struct Node* next;};

这里写图片描述

//程序清单12.10 queue.h#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; //maximum number of items in Queue    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.cpp#include "queue.h"#include <cstdlib>  //for rand()Queue::Queue(int qs) : qsize(qs){    front = rear = NULL;    items = 0;} Queue::~Queue(){    Node *temp;    while(front != NULL)    {        temp = front; //save address of front item        front = front->next;        delete temp; //delete former front    }}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;    add->item = item;    add->next = NULL;    items++;    if(front == NULL)        front = add;    else        rear->next = add;    rear = add;    return true;}bool Queue::dequeue(Item & item){    if(front == NULL)        return false;    item = front->item;    items--;    Node* temp = front; //save location of first item    front = front->next;    delete temp; //delete former first item    if(items == 0)        rear = NULL;    return true;}void Customer::set(long when){    processtime = std::rand()%3 + 1; //time set to a random value in the range 1 - 3    arrive = when;}

现在已经拥有模拟ATM所需的工具。程序允许用户输入3个数:队列的最大长度、程序模拟的持续时间以及平均每小时的客户数。程序将使用循环–每次循环代表一分钟。在每分钟的循环中,程序将完成下面的工作。
1. 判断是否来了新的客户。如果来了,并且此时队列未满,则将它添加到队列中,否则拒绝客户入队。
2. 如果没有客户在进行交易,则选取队列的第一个客户。确定该客户的已等候时间,并将wait_time计数器设置为新客户所需的处理时间。
3. 如果客户正在处理中,则将wait_time计数器减1.
4. 记录各种数据,如获得服务的客户数目、被拒绝的客户数目、排队等候的累积时间以及累积的队列长度等。
当模拟循环结束时,程序将报告各种统计结果。

//程序清单12.12 bank.cpp//compile with queue.cpp#include <iostream>#include <cstdlib> //for rand() and srand()#include <ctime> //for time()#include "queue.h"const int MIN_PER_HR = 60;bool newcustomer(double x); //is there a new customer?int main(){    using std::cin;    using std::cout;    using std::endl;    using std::ios_base;    std::srand(std::time(0));    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: ";    int hours;    cin >> hours;    long cyclelimit = MIN_PER_HR * hours;    cout << "Enter the average number of customers per hour: ";    double perhour;    cin >> perhour;    double min_per_cust; //average time between arrivals    min_per_cust = MIN_PER_HR / perhour;    Item temp;    long turnaways = 0;//turned away by full queue    long customers = 0;//joined the queue    long served = 0;//served during the simulation    long sum_line = 0; //cumulative line length    int wait_time = 0;//time until autoteller is free    long line_wait = 0; //cumulative time in line    //running the simulation    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();    }//reporting results    if(customers > 0)    {        cout << "customers 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;        cout << "average wait time: "             << (double) line_wait /served <<" minutes\n";    }    else        cout << "No customers!\n";    cout << "Done!\n";    return 0;}bool newcustomer(double x){    return (std::rand() * x/RAND_MAX < 1);    //rand() * x/RAND_MAX值位于0到x之间,1/x概率小于1,也即平均每隔x次,这个值会有一次小于1.}
0 0
原创粉丝点击