使用C++实现类似Java的对象引用的做法
我们知道C++是没有引用计数的,用指针可以灵活传递对象却必须手动管理内存,用栈变量可自动管理内存却有生存期限制。其实C++是非常强大的,用C++完全可以实现类似Java的对象引用的。鄙人才疏学浅,写错了请轻喷。

以下代码更改一处,这里是之前采用的代码,有疏漏,多谢@金星凌日 提醒
<code class="lang-cpp">MyClass &operator=(const MyClass& src) {
                                                            cout << "operator=" << endl;
    Dispose(); // 【不能处理自赋值情况】
    CopyFrom(src);
    return *this;
}</code></pre><pre data-tag="nkcsource" data-type="pre"><code class="lang-cpp">// MyRefClass.cpp : 定义控制台应用程序的入口点。
//
               
#include "stdafx.h"
               
#include <string.h>
#include <stdio.h>
#include <iostream>
using namespace std;
               
class MyClass { // 引用类的写法
private:
    void CopyFrom(const MyClass& src) {
                                                                cout << "copyfrom" << endl;
        if (src.pm_obj != NULL)
        {
            src.pm_obj->m_refcount++; // 当复制时增加计数并引用源对象
            this->pm_obj = src.pm_obj;
        }
    }
    void Dispose() {
                                                                cout << "dispose" << endl;
        if (this->pm_obj != NULL)
        {
            if (--this->pm_obj->m_refcount <=0) 当析构时减少计数             {                 disposedata(); 若计数减少到零则销毁对象                 delete this->pm_obj;
                this->pm_obj = NULL;
            }
        }
    }
                   
    // TODO: 真正的初始化函数(自己写)
    void InitData(char *str1){
                                                                cout << "initdata" << endl;
        this->pm_obj->resource = new char [strlen(str1)+20];
        strcpy(this->pm_obj->resource, str1);
    }
    // TODO: 真正的析构函数(自己写)
    void DisposeData() {
                                                                cout << "disposedata" << endl;
        delete [] this->pm_obj->resource;
        this->pm_obj->resource = NULL;
    }
               
public:
    // Big-3 的固定写法,不用解释
    MyClass &operator=(const MyClass& src) {
                                                                cout << "operator=" << endl;
        if (&src != this) { // 【更改】不是自赋值的话
            Dispose();
            CopyFrom(src);
        }
        return *this;
    }
    MyClass(const MyClass& src) {
                                                                cout << "copy" << endl;
        CopyFrom(src);
    }
    ~MyClass() {
                                                                cout << "delete" << endl;
        Dispose();
    }
    // 构造函数写法
    MyClass() {
                                                                cout << "new()" << endl;
        this->pm_obj = new MyClassBase; // 新建对象并将计数置为1
        this->pm_obj->m_refcount = 1;
        InitData("");
    }
    MyClass(char *str1) {
                                                                cout << "new(str)" << endl;
        this->pm_obj = new MyClassBase; // 新建对象并将计数置为1
        this->pm_obj->m_refcount = 1;
        InitData(str1);
    }
               
    // Dup函数(传统复制函数)可以不写
    MyClass Dup() {
                                                                cout << "dup" << endl;
        MyClass temp(this->pm_obj->resource); // 新建一个完全独立的对象并返回
        return temp;
    }
               
    // TODO: 此处添加其它成员函数以方便调用
    char *GetString() {
        return this->pm_obj->resource;
    }
               
    void *GetData() {
        return this->pm_obj;
    }
               
    int GetCount() {
        return this->pm_obj->m_refcount;
    }
               
private:
    // 引用类的变量仅此一份
    struct MyClassBase{
        int m_refcount;
               
        // TODO: 此处添加常规变量以方便保存状态
        char *resource;
               
    } *pm_obj;
};
               
               
int _tmain(int argc, _TCHAR* argv[])
{
    // 测试程序
    MyClass a;
    MyClass b = a;
    MyClass c;
    c = b;
    MyClass d=b.Dup();
    printf("%p %p %p %p\n",a.GetData(), b.GetData(), c.GetData(), d.GetData());
    printf("%p %p %p %p\n",a.GetString(), b.GetString(), c.GetString(), d.GetString());
    printf("%d %d %d %d\n",a.GetCount(), b.GetCount(), c.GetCount(), d.GetCount());
    return 0;
}</=0)></iostream></stdio.h></string.h></code></code>
捕获.PNG

[修改于 6 年前 - 2015-05-17 13:17:05]

来自:计算机科学 / 软件综合
 
1176764177
6年5个月前
1楼
我看了几天c++表示不是特难理解啊
为啥都说c++很难学难道是因为mfc么
我反正只是用c++给mcu
回复
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan作者
6年5个月前
2楼
引用 1176764177:
我看了几天c++表示不是特难理解啊
为啥都说c++很难学难道是因为mfc么
我反正只是用c++给mcu
实际上C++98并不比C语言难多少,C++11有点杂糅的感觉,并且很多东西还用不了,这个比较蛋疼。
MFC难学主要是因为把WinMain给封装起来了,并且有很多特殊的元素,然后想要更高级的操作还要学WinAPI和COM等很多东西。
回复
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
1176764177
6年5个月前
3楼
引用 acmilan:
实际上C++98并不比C语言难多少,C++11有点杂糅的感觉,并且很多东西还用不了,这个比较蛋疼。
MFC难学主要是因为把WinMain给封装起来了,并且有很多特殊的元素,然后想要更高级的操作还要学WinAPI和COM等很多东西。
98和11标准相差很大??
iar用的是那个标准?
我一般也就是用函数重载还有能随处定义变量这2点
mfc我没学一般不给pc写程序
要学貌似qt比较万金油吧
回复
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan作者
6年5个月前
4楼
引用 1176764177:
98和11标准相差很大??
iar用的是那个标准?
我一般也就是用函数重载还有能随处定义变量这2点
mfc我没学一般不给pc写程序
要学貌似qt比较万金油吧
C++11向下兼容C++98,不管在哪里用C++98都可以使用,iar应该也支持C++98。
C++11其实是多了一些语法糖,比如lambda表达式、for遍历语法等,然后库的变化比较大。
现在已经发展到C++14了,C++17也在制定中
回复
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
.........
6年5个月前
5楼
Qt跨平台优势大。编译器执行标准应该式是可以指定的。
回复
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan作者
6年5个月前 修改于 6年5个月前
6楼
引用 .........:
Qt跨平台优势大。编译器执行标准应该式是可以指定的。
至于GUI框架,我觉得如果只在Windows上用的话,用MFC比较好。跨平台的话,用wxWidget或Qt都是可以的。

对于C++标准的版次,保证代码兼容性比较重要,新的不一定好,很多开源软件直到2009年都在继续支持VC6
回复
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan作者
6年5个月前
7楼
引用 1176764177:
98和11标准相差很大??
iar用的是那个标准?
我一般也就是用函数重载还有能随处定义变量这2点
mfc我没学一般不给pc写程序
要学貌似qt比较万金油吧
其实windows上的程序,跨平台的只是少数,不然linus要高兴死了。
回复
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
1176764177
6年5个月前
8楼
引用 acmilan:
其实windows上的程序,跨平台的只是少数,不然linus要高兴死了。
了解了就是看上qt支持linux所以。。
回复
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
金星凌日
6年5个月前
9楼
我记得C++ Primer里面就有一个例子。
另外,你这个赋值操作符似乎有点问题。
回复
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
张静茹
6年5个月前
10楼
引用 1176764177:
我看了几天c++表示不是特难理解啊
为啥都说c++很难学难道是因为mfc么
我反正只是用c++给mcu
C++语法复杂, :: -> . C#只有 一个 .
回复
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan作者
6年5个月前
11楼
引用 金星凌日:
我记得C++ Primer里面就有一个例子。
另外,你这个赋值操作符似乎有点问题。
C++ Primer里确实有。。。在第421页
什么问题。。。有问题就是有问题,不要似乎
回复
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
金星凌日
6年5个月前
12楼
引用 acmilan:
C++ Primer里确实有。。。在第421页
什么问题。。。有问题就是有问题,不要似乎
你这个赋值操作符不能处理这样的情况:

<code class="lang-cpp">MyClass a;
a=a;</code>
我记得C++里是要考虑这种问题的。
回复
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan作者
6年5个月前
13楼
引用 金星凌日:
你这个赋值操作符不能处理这样的情况:

MyClass a;
a=a;我记得C++里是要考虑这种问题的。
嗯。。。多谢指教
回复
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan作者
6年5个月前
14楼
更改一处,多谢@金星凌日 提醒
<code class="lang-cpp">MyClass &operator=(const MyClass& src) {
                                                            cout << "operator=" << endl;
    if (&src != this) { // 更改的地方
        Dispose();
        CopyFrom(src);
    }
    return *this;
}</code></pre></code>
回复
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan作者
6年5个月前
15楼
引用 acmilan:
嗯。。。多谢指教
C++我是看某人的blog学的,不是看C++ Primer学的,不是太扎实,标准库都不会用→_→
回复
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan作者
6年5个月前
16楼
引用 张静茹:
C++语法复杂, :: -> . C#只有 一个 .
你可以看看C++/CLI的语法,不忍直视→_→
回复
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan作者
6年5个月前
17楼
引用 1176764177:
98和11标准相差很大??
iar用的是那个标准?
我一般也就是用函数重载还有能随处定义变量这2点
mfc我没学一般不给pc写程序
要学貌似qt比较万金油吧
另外要是给MCU用的话,STL也是非常好用的
回复
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
张静茹
6年5个月前
18楼
引用 acmilan:
你可以看看C++/CLI的语法,不忍直视→_→
C++/CLI的语法一样很难
回复
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan作者
6年5个月前
19楼
引用 张静茹:
C++/CLI的语法一样很难
C++/CLI的语法十分混乱和难以理解。。。主要是要兼容C++语言所以搞得很复杂
回复
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
金星凌日
6年5个月前
20楼
引用 1176764177:
98和11标准相差很大??
iar用的是那个标准?
我一般也就是用函数重载还有能随处定义变量这2点
mfc我没学一般不给pc写程序
要学貌似qt比较万金油吧
实际上Qt使用的并不完全是C++。使用Qt的源代码要经过moc处理才可以交给C++编译器编译。

至于C++98和C++11的差别,一本介绍C++11新增内容的书就已经接近300页了。
回复
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
1176764177
6年5个月前
21楼
引用 金星凌日:
实际上Qt使用的并不完全是C++。使用Qt的源代码要经过moc处理才可以交给C++编译器编译。

至于C++98和C++11的差别,一本介绍C++11新增内容的书就已经接近300页了。
只要向下兼容就好说。。
回复
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论

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

所属专业
上级专业
同级专业
acmilan
进士 学者 笔友
文章
465
回复
2927
学术分
4
2009/05/30注册,3 年前活动
暂无简介
%7B%22isDisplay%22%3Atrue%7D

仅供内部学术交流或培训使用,请先保存到本地。本内容不代表科创观点,未经原作者同意,请勿转载。

下载

插入资源
全部
图片
视频
音频
附件
全部
未使用
已使用
正在上传
空空如也~
上传中..{{f.progress}}%
处理中..
上传失败,点击重试
等待中...
{{f.name}}
空空如也~
(视频){{r.oname}}
{{selectedResourcesId.indexOf(r.rid) + 1}}
处理中..
处理失败
插入表情
我的表情
共享表情
Emoji
上传
注意事项
最大尺寸100px,超过会被压缩。为保证效果,建议上传前自行处理。
建议上传自己DIY的表情,严禁上传侵权内容。
点击重试等待上传{{s.progress}}%处理中...已上传
空空如也~
草稿箱
加载中...
此处只插入正文,如果要使用草稿中的其余内容,请点击继续创作。
{{fromNow(d.toc)}}
{{getDraftInfo(d)}}
标题:{{d.t}}
内容:{{d.c}}
继续创作
删除插入插入
{{forum.displayName}}
{{forum.countThreads}}
篇文章,
{{forum.countPosts}}
条回复
{{forum.description || "暂无简介"}}
ID: {{user.uid}}
学术分隐藏
{{submitted?"":"投诉或举报"}}
请选择违规类型:
{{reason.description}}
支持的图片格式:jpg, jpeg, png
插入公式
分享回复:{{shareId}}
加载中...
评论控制
加载中...
文号:{{pid}}
加载中...
详情
详情
推送到专栏从专栏移除
设为匿名取消匿名
查看作者
回复
只看作者
加入收藏取消收藏
加入关注取消关注
折叠回复
置顶取消置顶
评学术分
鼓励
设为精选取消精选
建议修改
编辑
通过审核
评论控制
退修或删除
历史版本
违规记录
投诉或举报
加入黑名单移除黑名单
查看IP
{{format('YYYY/MM/DD HH:mm:ss', toc)}}
下载资料
{{fileName}}
大小:{{size}}
下载当前附件将花费 {{costMessage}}
{{description}}
你当前剩余 {{holdMessage}}
{{fileName}}
大小:{{size}}
当前附件免费。
你已购买过此附件,下载当前附件不需要花费积分。
加载中...
{{errorInfo}}
附件已丢失
当前账号的附件下载数量限制如下:
时段 个数
{{f.startingTime}}点 - {{f.endTime}}点 {{f.fileCount}}