C++定式模型 - 解决Big Three问题的方法
acmilan2015/04/25软件综合 IP:四川
对于C++初学者来说最头疼的,肯定就是Big Three了,因为这其实是C++比较蛋疼的一个地方,提升了灵活性但增大了耦合性,不过还是有办法解决它的。

所谓Big Three是指『复杂C++类』(指管理有外部资源的基类,如CFile,CArray,CString等)必须具有如下的功能:
1.赋值运算符
2.复制构造函数
3.析构函数

但是,实际上它们通常具有如下关系:
赋值运算符 = 析构函数 + 复制构造函数

为了降低耦合性,需要重新组合它们的功能,解决办法是:

一、建立两个模拟函数:CopyFrom和Dispose
·在Dispose中,丢弃所有资源
·在CopyFrom中,复制内存(memcpy)及所有资源

二、在默认构造函数中,事先清空数据(memset)为0,并进行必要的初始化,清除垃圾数据

三、建立C++定式模型
·在复制构造函数中,调用CopyFrom
·在析构函数中,调用Dispose
·在operator=中,调用Dispose和CopyFrom

这个模型适用于『复杂的C++类』,仅包括自释放成员的简单C++类不需要这个模型。
这种方法实际上有效地实现了类似其它高级语言的复制机制。
模式并非一成不变,如果你不需要某种功能,完全可以砍掉,更可以进一步地修改以符合自己的需求。

<code class="lang-cpp">class MyClass
{
private:
    // 两个模拟函数
    void CopyFrom(MyClass& src);
    void Dispose();
     
public:
    // 需要自己写的函数
    MyClass(); // 默认构造函数(清空内存并设置默认值)
    MyClass(int a, int b, char *str); // 常规构造函数
     
public:
    // C++定式模型:丢弃旧的,拷贝新的
    ~MyClass() { Dispose(); } // 析构函数(丢弃旧的)
    MyClass(MyClass& src) { CopyFrom(src); } // 复制构造函数(拷贝新的)
    MyClass& operator=(MyClass& src) { // 赋值运算符(丢弃旧的,拷贝新的)
        Dispose();
        CopyFrom(src);
        return *this;
    }
     
public:
    int a;
    int b;
    char *str;
};
     
// 【CopyFrom函数】作用:复制内存和外部资源
void MyClass::CopyFrom(MyClass& src)
{
    // 复制内存
    memcpy(this, &src, sizeof(MyClass));
     
    // 复制外部资源
    // 先判断是否来了新资源,如果来了则复制
    if (src.str != NULL) {
        this->str = new char[strlen(src.str)+1];
        strcpy(this->str, src.str);
    }
}
     
// 【Dispose函数】作用:销毁旧资源
void MyClass::Dispose()
{
    if (this->str != NULL)   // 判断是否存在旧资源
    {
        delete[] this->str; // 删除旧资源
    }
}
     
// 【默认构造函数】
// 任务:清空内存,设置默认值
MyClass::MyClass() {
    memset(this, 0, sizeof(MyClass));
    // TODO: 设置默认值
}
     
     
// 【常规构造函数】
// 任务:按照常规方法初始化数据
MyClass::MyClass(int a, int b, char *str)
{
    this->a = a;
    this->b = b;
     
    if (str != NULL) {
        this->str = new char[strlen(str)+1];
        strcpy(this->str, str);
    } else {
        // 注意:常规构造函数需要初始化所有成员,防止产生垃圾数据
        this->str = NULL;
    }
}</code>

[修改于 9年8个月前 - 2015/04/28 01:21:05]

来自:计算机科学 / 软件综合
4
已屏蔽 原因:{{ notice.reason }}已屏蔽
{{notice.noticeContent}}
~~空空如也
acmilan 作者
9年8个月前 修改于 9年8个月前 IP:四川
764862
当然,如果你想做一个“不动性赋值”特性的C++类(即赋值运算符只传递状态而不传递对象本身,类似VB6风格)
——这不属于通常意义上的赋值运算符的功能。。。就别用这个模型了,乖乖地写Big Three吧
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan作者
9年8个月前 IP:四川
764876
当然如果懒得写的话,也可以直接把复制构造函数和赋值运算符都设为private(不用编写代码)
对于文件、网络连接等不可复制资源,可以专门写一个全局类统一管理它们的生命周期,而不是由各个类自行管理
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan作者
9年7个月前 IP:四川
769106
修正一处,多谢@金星凌日 提醒
<code class="lang-cpp">class MyClass
{
private:
    // 两个模拟函数
    void CopyFrom(MyClass& src);
    void Dispose();
        
public:
    // 需要自己写的函数
    MyClass(); // 默认构造函数(清空内存并设置默认值)
    MyClass(int a, int b, char *str); // 常规构造函数
        
public:
    // C++定式模型:丢弃旧的,拷贝新的
    ~MyClass() { Dispose(); } // 析构函数(丢弃旧的)
    MyClass(MyClass& src) { CopyFrom(src); } // 复制构造函数(拷贝新的)
    MyClass& operator=(MyClass& src) { // 赋值运算符(丢弃旧的,拷贝新的)
        if (&src != this) { // 【修正】:判断自赋值情况
            Dispose();
            CopyFrom(src);
        }
        return *this;
    }
        
public:
    int a;
    int b;
    char *str;
};</code>
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论

想参与大家的讨论?现在就 登录 或者 注册

所属专业
上级专业
同级专业
acmilan
进士 学者 笔友
文章
461
回复
2934
学术分
4
2009/05/30注册,5年10个月前活动
暂无简介
主体类型:个人
所属领域:无
认证方式:邮箱
IP归属地:未同步
文件下载
加载中...
{{errorInfo}}
{{downloadWarning}}
你在 {{downloadTime}} 下载过当前文件。
文件名称:{{resource.defaultFile.name}}
下载次数:{{resource.hits}}
上传用户:{{uploader.username}}
所需积分:{{costScores}},{{holdScores}}下载当前附件免费{{description}}
积分不足,去充值
文件已丢失

当前账号的附件下载数量限制如下:
时段 个数
{{f.startingTime}}点 - {{f.endTime}}点 {{f.fileCount}}
视频暂不能访问,请登录试试
仅供内部学术交流或培训使用,请先保存到本地。本内容不代表科创观点,未经原作者同意,请勿转载。
音频暂不能访问,请登录试试
支持的图片格式:jpg, jpeg, png
插入公式
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

加载中...
详情
详情
推送到专栏从专栏移除
设为匿名取消匿名
查看作者
回复
只看作者
加入收藏取消收藏
收藏
取消收藏
折叠回复
置顶取消置顶
评学术分
鼓励
设为精选取消精选
管理提醒
编辑
通过审核
评论控制
退修或删除
历史版本
违规记录
投诉或举报
加入黑名单移除黑名单
查看IP
{{format('YYYY/MM/DD HH:mm:ss', toc)}}