拷贝控制示例

在本片文章中,我们将概述两个类的设计,这两个类可以用于邮件处理应用中。(消息处理示例)
提供两个类名Message和Folder,分别表示一种类型的消息和消息目录。每个Message对象可以出现在多个Folder中。但是任意给定的Message的内容只有一个副本。这样,如果一条Message的内容被改变,则我们从他所在的任何Folder来浏览此Message时,都会看到改变后的内容。
为了记录Message位于哪些Folder中,每个Message都会保存一个它所在Folder的指针的set。同样的每个Folder都保存一个它包含的Message的指针set。

Message类:

#pragma once
#include<string>
#include<set>
using namespace std;

class Message {
    friend class Folder;
public:
    explicit Message(const string &str = "") :
        contents(str) {}

    Message(const Message&);
    Message& operator=(const Message&);
    ~Message();

    void addFldr(Folder *);     //添加给定的Folder
    void remFldr(Folder *);     //删除给定的Folder
    //从给定的Folder集合中添加、删除Message
    void save(Folder&);
    void remove(Folder&);
private:
    string contents;          //实际消息文本
    set<Folder*>folders;      //包含本Message的Folder

                              //拷贝构造函数、拷贝赋值运算符和析构函数所使用的工具函数
                              //将本Message添加到指向参数的Folder中
    void add_to_Folders(const Message&);

    //从folders中的每个Folder中删除本Message
    void remove_from_Folders();
};

上述中提供了save和remove操作,来向一个给定Folder添加一条Message或是从中删除一条Message。

void Message::save(Folder &f)
{
    folders.insert(&f);                                  //将给定的folder添加到我们的Folder列表中
    f.addMsg(this);                                      //将Message添加到f的Message集合中
}

void Message::remove(Folder &f)
{
    folders.erase(&f);                                   //将给定Folder 从我们的Folder列表中删除
    f.remMsg(this);                                      //将Message从f的Message集合中删除
}

当我们拷贝一个Message时,副本和原对象将是不同的Message对象,但两个Message都出现在相同的Folder中。因此,拷贝Message的操作包括消息内容的拷贝和Folder指针set的拷贝。并且我们必须在每个包含此消息的Folder中都添加一个指向新创建的Message指针。

void Message::add_to_Folders(const Message &m)
{
    for (auto f : m.folders)                           //对于每个包含m的Folder,向该Folder添加一个指向本Message的指针
        f->addMsg(this);
}

Message::Message(const Message &m):
    contents(m.contents),folders(m.folders)
{
    add_to_Folders(m);
}

但我们销毁一个Message时,它将不复存在,所以我们必须在,包含此Message的Folder中删除指向此消息的指针。
对于拷贝构造函数和析构函数的说明,如果我们使用合成的版本,可以简单的实现拷贝每个数据成员或销毁。但是当我们拷贝一个Message时不仅要拷贝,还要将此消息添加到对应的Folder中(调用addMsg)。同理,当销毁时,需要从他所在的Folders中删除(调用remMsg)。

void Message::remove_from_Folders()
{
    for (auto f : folders)
        f->remMsg(this);                             //对folders中的每个指针,从该Folder中删除本Message
}

Message::~Message()
{
    remove_from_Folders();
}

当我们讲一个Message对象赋予另一个对象时,左侧Message的内容会被右侧Message的内容所代替。并且此时,我们必须更新Folder集合,从原来包含左侧Message的Folder中将它删除,并将它添加到包含右侧消息的Folder中。

Message &Message::operator=(const Message &rhs)
{
    //通过先删除指针再插入它们,来处理自赋值的情况
    remove_from_Folders();
    contents = rhs.contents;
    folders = rhs.folders;
    add_to_Folders(rhs);
    return *this;
}

对于Message另外两个成员函数添加给定的Folder和删除给定的Folder,定义如下:

void Message::addFldr(Folder*f)
{
    folders.insert(f);
}

void Message::remFldr(Folder*f)
{
    folders.erase(f);
}

对于Folder类的定义如下:

#pragma once
#include"Message.h"

class Folder {
public:
    void addMsg(Message *m) { msgs.insert(m); }
    void remMsg(Message *m) { msgs.erase(m); }
    Folder(const Folder&);
    Folder& operator=(const Folder&);
    ~Folder();
private:
    set<Message*> msgs;
    void add_to_Message(const Folder&);              //将这个Folder添加到所有的Message中
    void remove_from_Msgs();                        //把这个Folder从所有的Message中删除
};

首先实现了Message类用到的两个函数,将消息添加和删除文件夹。此外,Folder也应该有将自身添加到和删除出所有的Message的foldes集合中的成员函数,定义如下:

void Folder::add_to_Message(const Folder &f)
{
    for (auto msg : f.msgs)
        msg->addFldr(this);
}


void Folder::remove_from_Msgs()
{
    while (!msgs.empty())
    {
        (*msgs.begin())->remove(*this);
    }
}

对于Folder的拷贝构造函数,它首先拷贝msgs集合,然后调用add_to_Message将其添加到它所有的Message的folders集合中。

Folder::Folder(const Folder &f)  :msgs(f.msgs)
{
    add_to_Message(f);
}

析构函数调用remove_from_Msgs从所有Message中删除本Folder

Folder::~Folder()
{
    remove_from_Msgs();
}

拷贝赋值运算符首先将Folder从每个旧的Message中删除,然后从右侧Folder拷贝Message集合,最后将自身添加到每个新Message中。

Folder& Folder::operator=(const Folder&f)
{
    remove_from_Msgs();
    msgs = f.msgs;
    add_to_Message(f);
    return *this;
}

综合代码如下:

Message类的定义

#pragma once
#include<string>
#include<set>
using namespace std;

class Message {
    friend class Folder;
public:
    explicit Message(const string &str = "") :
        contents(str) {}

    Message(const Message&);
    Message& operator=(const Message&);
    ~Message();

    void addFldr(Folder *);     //添加给定的Folder
    void remFldr(Folder *);     //删除给定的Folder
    //从给定的Folder集合中添加、删除Message
    void save(Folder&);
    void remove(Folder&);

    void show();
private:
    string contents;          //实际消息文本
    set<Folder*>folders;      //包含本Message的Folder

                              //拷贝构造函数、拷贝赋值运算符和析构函数所使用的工具函数
                              //将本Message添加到指向参数的Folder中
    void add_to_Folders(const Message&);

    //从folders中的每个Folder中删除本Message
    void remove_from_Folders();
};



Message类的成员函数定义

#include"Folder.h"
#include"Message.h"




void Message::addFldr(Folder*f)
{
    folders.insert(f);
}

void Message::remFldr(Folder*f)
{
    folders.erase(f);
}

void Message::save(Folder &f)
{
    folders.insert(&f);                                  //将给定的folder添加到我们的Folder列表中
    f.addMsg(this);                                      //将Message添加到f的Message集合中
}

void Message::remove(Folder &f)
{
    folders.erase(&f);                                   //将给定Folder 从我们的Folder列表中删除
    f.remMsg(this);                                      //将Message从f的Message集合中删除
}

void Message::add_to_Folders(const Message &m)
{
    for (auto f : m.folders)                           //对于每个包含m的Folder,向该Folder添加一个指向本Message的指针
        f->addMsg(this);
}

Message::Message(const Message &m):
    contents(m.contents),folders(m.folders)
{
    add_to_Folders(m);
}

void Message::remove_from_Folders()
{
    for (auto f : folders)
        f->remMsg(this);                             //对folders中的每个指针,从该Folder中删除本Message
}

Message::~Message()
{
    remove_from_Folders();
}

Message &Message::operator=(const Message &rhs)
{
    remove_from_Folders();
    contents = rhs.contents;
    folders = rhs.folders;
    add_to_Folders(rhs);
    return *this;
}

void Message::show()
{
    cout << "folders的个数有:" << folders.size() << endl;
}

Folder类的定义:

#pragma once
#include"Message.h"

class Folder {
public:
    void addMsg(Message *m) { msgs.insert(m); }
    void remMsg(Message *m) { msgs.erase(m); }
    Folder(const Folder&);
    Folder& operator=(const Folder&);
    ~Folder();
    void show();
private:
    set<Message*> msgs;
    void add_to_Message(const Folder&);              //将这个Folder添加到所有的Message中
    void remove_from_Msgs();                        //把这个Folder从所有的Message中删除
};

Folder类的成员函数的定义

#include"Folder.h"
#include"Message.h"

void Folder::add_to_Message(const Folder &f)
{
    for (auto msg : f.msgs)
        msg->addFldr(this);
}


void Folder::remove_from_Msgs()
{
    while (!msgs.empty())
    {
        (*msgs.begin())->remove(*this);
    }
}

Folder::Folder(const Folder &f)  :msgs(f.msgs)
{
    add_to_Message(f);
}

Folder::~Folder()
{
    remove_from_Msgs();
}

Folder& Folder::operator=(const Folder&f)
{
    remove_from_Msgs();
    msgs = f.msgs;
    add_to_Message(f);
    return *this;
}
void Folder::show()
{
    cout << "msgs的个数有:" << msgs.size() << endl;
}

最后写一个样例测试一下:

#include"Folder.h"
#include"Message.h"
#include<iostream>

int main()
{
    string s1("hello1");
    string s2("hello2");
    string s3("hello3");
    string s4("hello4");
    string s5("hello5");
    string s6("hello6");

    // all new messages, no copies yet  
    Message m1(s1);
    Message m2(s2);
    Message m3(s3);
    Message m4(s4);
    Message m5(s5);
    Message m6(s6);

    Folder f1;
    Folder f2;


    m1.save(f1); m3.save(f1); m5.save(f1);
    m1.save(f2);
    m2.save(f2); m4.save(f2); m6.save(f2);


    cout << "m1到m6中folders的个数:" << endl;
    m1.show(); m2.show(); m3.show();
    m4.show(); m5.show(); m6.show();
    cout << endl;
    cout << "f1到f2中Message的个数:" << endl;
    f1.show(); f2.show();
    cout << endl;

    // create some copies  
    Message c1(m1);
    Message c2(m2), c4(m4), c6(m6);

    cout << "after create some copies: " << endl;
    cout << "m1到m6中folders的个数:" << endl;
    m1.show(); m2.show(); m3.show();
    m4.show(); m5.show(); m6.show();
    cout << endl;
    cout << "f1到f2中Message的个数:" << endl;
    f1.show(); f2.show();
    cout << endl;
    cout << "c1,c2,c4,c6中folders的个数:" << endl;
    c1.show(); c2.show();
    c4.show(); c6.show();
    cout << endl;

    // now some assignments  
    m2 = m3;
    m4 = m5;
    m6 = m3;
    m1 = m5;

    cout << "after  some assignments: " << endl;
    cout << "m1到m6中folders的个数:" << endl;
    m1.show(); m2.show(); m3.show();
    m4.show(); m5.show(); m6.show();
    cout << endl;
    cout << "f1到f3中Message的个数:" << endl;
    f1.show(); f2.show();
    cout << endl;
    cout << "c1,c2,c4,c6中folders的个数:" << endl;
    c1.show(); c2.show();
    c4.show(); c6.show();

    getchar();
}

结果如下:
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值