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

以下代码更改一处,这里是之前采用的代码,有疏漏,多谢@金星凌日 提醒
MyClass &operator=(const MyClass& src) {
                                                            cout << "operator=" << endl;
    Dispose(); // 【不能处理自赋值情况】
    CopyFrom(src);
    return *this;
}</code></pre><pre data-tag="nkcsource" data-type="pre">// 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>// 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>
捕获.png

[修改于 9年9个月前 - 2015/05/17 13:17:05]

来自:计算机科学 / 软件综合
22
 
已屏蔽 原因:{{ notice.reason }}已屏蔽
{{notice.noticeContent}}
~~空空如也
1176764177
9年9个月前 IP:北京
768961
我看了几天c++表示不是特难理解啊
为啥都说c++很难学难道是因为mfc么
我反正只是用c++给mcu
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan作者
9年9个月前 IP:四川
768965
引用 1176764177:
我看了几天c++表示不是特难理解啊
为啥都说c++很难学难道是因为mfc么
我反正只是用c++给mcu
实际上C++98并不比C语言难多少,C++11有点杂糅的感觉,并且很多东西还用不了,这个比较蛋疼。
MFC难学主要是因为把WinMain给封装起来了,并且有很多特殊的元素,然后想要更高级的操作还要学WinAPI和COM等很多东西。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
1176764177
9年9个月前 IP:北京
768967
引用 acmilan:
实际上C++98并不比C语言难多少,C++11有点杂糅的感觉,并且很多东西还用不了,这个比较蛋疼。
MFC难学主要是因为把WinMain给封装起来了,并且有很多特殊的元素,然后想要更高级的操作还要学WinAPI和COM等很多东西。
98和11标准相差很大??
iar用的是那个标准?
我一般也就是用函数重载还有能随处定义变量这2点
mfc我没学一般不给pc写程序
要学貌似qt比较万金油吧
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan作者
9年9个月前 IP:四川
768968
引用 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字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
.........
9年9个月前 IP:江西
768969
Qt跨平台优势大。编译器执行标准应该式是可以指定的。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan作者
9年9个月前 修改于 9年9个月前 IP:四川
768971
引用 .........:
Qt跨平台优势大。编译器执行标准应该式是可以指定的。
至于GUI框架,我觉得如果只在Windows上用的话,用MFC比较好。跨平台的话,用wxWidget或Qt都是可以的。

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

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

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

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

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

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

所属专业
上级专业
同级专业
acmilan
进士 学者 笔友
文章
461
回复
2934
学术分
4
2009/05/30注册,5年11个月前活动
暂无简介
主体类型:个人
所属领域:无
认证方式:邮箱
IP归属地:未同步
插入公式
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

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