《C++ Primer Plus》第12章学习笔记

2021-07-20  本文已影响0人  蓬篙人

类和动态内存

第12章 类和动态内存

1. 动态内存和类

本章先从一个错误的字符串类设计来揭示在C++类设计中可能存在的问题,特别是在使用动态内存的情况。错误代码示例(使用 VS 2019):

// stringbad.h -- flawed string class definition
#pragma once

#include <iostream>

class StringBad
{
private:
    char* str;               
    int len;
    //////////类声明中不能初始化静态成员变量
    static int num_strings;
public:
    StringBad(const char* s);    
    StringBad();                 
    ~StringBad();                
    // friend function
    friend std::ostream& operator<<(std::ostream& os, const StringBad& st);
};
// stringbad.cpp -- StringBad class methods

#include <cstring>   // string.h for some
#include "stringbad.h"

using std::cout;

//////////// 初始化静态类成员(注意这里使用了作用域操作符)
int StringBad::num_strings = 0;

// construct StringBad from c string
StringBad::StringBad(const char* s)
{
    len = std::strlen(s);
    str = new char[len + 1];
    //std::strcpy(str, s);
    strcpy_s(str, len + 1, s);
    num_strings++;
    cout << num_strings << ": \"" << str << "\" object created\n";
}

StringBad::StringBad()
{
    len = 4;
    str = new char[4];
    //std::strcpy(str, "C++");
    strcpy_s(str, len, "C++");
    num_strings++;
    cout << num_strings << ": \"" << str << "\" default object created\n";
}

StringBad::~StringBad()
{
    cout << "\"" << str << "\" object deleted, ";
    --num_strings;
    cout << num_strings << " left\n";
    delete[] str;
}

std::ostream& operator<<(std::ostream& os, const StringBad& st)
{
    os << st.str;
    return os;
}
// vegnews.cpp -- using new and delete with classes

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

using std::cout;

void callme1(StringBad&);  // pass by reference
void callme2(StringBad);   // pass by value

int main()
{
    using std::endl;
    StringBad headline1("Celery Stalks at Midnight");
    StringBad headline2("Letture Prey");
    StringBad sports("Spinach Leaves Bowl for Dollars");

    cout << "headline1: " << headline1 << endl;
    cout << "headline2: " << headline2 << endl;
    cout << "sports: " << sports << endl;

    callme1(headline1);
    cout << "headline1: " << headline1 << endl;
    /////////// 调用了隐式的复制构造函数!!!
    callme2(headline2);
    cout << "headline2: " << headline2 << endl;
    cout << "Initialize one object to another: \n";
    /////////// 调用了隐式的复制构造函数!!!
    StringBad sailor = sports;
    cout << "Sailor: " << sailor << endl;
    cout << "Assign one object to another: \n";
    StringBad knot;
    /////////// 调用隐式的重载赋值(=)操作符!!!
    knot = headline1;
    cout << "Knot: " << knot << endl;
    cout << "End of main()\n";

    return 0;
}

void callme1(StringBad& rsb)
{
    cout << "String passed by reference: \n";
    cout << "    \"" << rsb << "\"\n";
}

//////// 按值传递:调用隐式复制构造函数,生成类的一个临时对象。函数结束后调用参数sb的析构函数!!!
void callme2(StringBad sb)
{
    cout << "String passed by value: \n";
    cout << "    \"" << sb << "\"\n";
}
Class_name(const Class_name&);
Class_name & Class_name::operator=(const Class_name& );

2. 队列模拟

Queue::Queue(int qa) : qsize(qs)
{
    // ...
}
class Queue
{
private:
    const int qszie;
    // 阻止公开复制
    Queue(const Queue& q) : qsize(0) { }
    Queue& operator=(const Queue& q) { return *this; }
    ...
}

//-----------
Queue snick(nip);    // 不允许
ruck = nip;          // 不允许
// 顾客类声明
class Customer
{
private:
    long arrive;      // 顾客到达时间
    int proceetime;   // 处理时间
public:
    Customer() { arrive = proceetime = 0; }
    void set(long when);
    long when() const { return arrive; }
    int ptime() const { return proceetime; }
};
// 顾客类实现
#include <cstdlib>
#include "Customer.h"

void Customer::set(long when)
{
    proceetime = std::rand() % 3 + 1;
    arrive = when;
}
// 队列类声明
#include "Customer.h"

typedef Customer Item;

class Queue
{
private:
    // class scope definitions
    // 嵌套结构:用于构造内部链表
    struct Node { Item item; struct Node* next; };
    enum { Q_SIZE = 10 };
    // private class member
    Node* front;     // pointer to front Queue
    Node* rear;      // pointer to rear of Queue
    int items;       // current number of items in Queue
    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);   // create queue with a qs limit
    ~Queue();
    bool isempty() const;
    bool isfull() const;
    int queuecount() const;
    bool enqueue(const Item& item); // add item to end
    bool dequeue(Item& item);       // remove item from front
};
// 队列类实现
#include <cstddef>
#include "Queue.h"

// 使用成员初始化列表初始化常量成员qsize
Queue::Queue(int qs) : qsize(qs)  // initialize qsize to qs
{
    front = rear = NULL;
    items = 0;
}

Queue::~Queue()
{
    Node* temp;
    // 因为入列时使用动态内存,因此析构需delete所有节点
    while (front != NULL)
    {
        temp = front;           // save address of front item
        front = front->next;   // reset pointer to next item
        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;
}

// add item to queue
bool Queue::enqueue(const Item& item)
{
    if (isfull())
        return false;
    // 使用动态内存创建Node结构
    Node* add = new Node;   
    if (add == NULL)
        return false;
    add->item = item;
    add->next = NULL;
    items++;
    if (front == NULL)
        front = add;
    else
        rear->next = add;
    rear = add;

    return true;
}

// place front item into item variable and remove from queue
bool Queue::dequeue(Item& item)
{
    if (front == NULL)
        return false;
    item = front->item;   // set item to first item in queue
    items--;
    Node* temp = front;   // save location of first item
    front = front->next;  // reset front to next item
    // 因为入列时使用动态内存,因此出列需要使用delete
    delete temp;          
    if (items == 0)
        rear = NULL;

    return true;
}
上一篇 下一篇

猜你喜欢

热点阅读