使用C++实现类似Java的对象引用的做法

文 号

t71509

21 回复 / 1563 浏览


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

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

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


11767641773 年前 -2015-05-16 20:34768961 1阶
我看了几天c++表示不是特难理解啊
为啥都说c++很难学难道是因为mfc么
我反正只是用c++给mcu

acmilan3 年前 -2015-05-16 20:40768965 2阶
引用 1176764177:
我看了几天c++表示不是特难理解啊
为啥都说c++很难学难道是因为mfc么
我反正只是用c++给mcu
实际上C++98并不比C语言难多少,C++11有点杂糅的感觉,并且很多东西还用不了,这个比较蛋疼。
MFC难学主要是因为把WinMain给封装起来了,并且有很多特殊的元素,然后想要更高级的操作还要学WinAPI和COM等很多东西。

11767641773 年前 -2015-05-16 20:44768967 3阶
引用 acmilan:
实际上C++98并不比C语言难多少,C++11有点杂糅的感觉,并且很多东西还用不了,这个比较蛋疼。
MFC难学主要是因为把WinMain给封装起来了,并且有很多特殊的元素,然后想要更高级的操作还要学WinAPI和COM等很多东西。
98和11标准相差很大??
iar用的是那个标准?
我一般也就是用函数重载还有能随处定义变量这2点
mfc我没学一般不给pc写程序
要学貌似qt比较万金油吧

acmilan3 年前 -2015-05-16 20:47768968 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也在制定中

.........3 年前 -2015-05-16 20:51768969 5阶
Qt跨平台优势大。编译器执行标准应该式是可以指定的。

acmilan3 年前 -2015-05-16 21:00768971 6阶
引用 .........:
Qt跨平台优势大。编译器执行标准应该式是可以指定的。
至于GUI框架,我觉得如果只在Windows上用的话,用MFC比较好。跨平台的话,用wxWidget或Qt都是可以的。

对于C++标准的版次,保证代码兼容性比较重要,新的不一定好,很多开源软件直到2009年都在继续支持VC6

[修改于 3 年前 - 2015-05-16 21:38:04]


acmilan3 年前 -2015-05-16 21:24768976 7阶
引用 1176764177:
98和11标准相差很大??
iar用的是那个标准?
我一般也就是用函数重载还有能随处定义变量这2点
mfc我没学一般不给pc写程序
要学貌似qt比较万金油吧
其实windows上的程序,跨平台的只是少数,不然linus要高兴死了。

11767641773 年前 -2015-05-16 22:22769002 8阶
引用 acmilan:
其实windows上的程序,跨平台的只是少数,不然linus要高兴死了。
了解了就是看上qt支持linux所以。。

金星凌日3 年前 -2015-05-17 10:03769063 9阶
我记得C++ Primer里面就有一个例子。
另外,你这个赋值操作符似乎有点问题。

张静茹3 年前 -2015-05-17 10:42769071 10阶
引用 1176764177:
我看了几天c++表示不是特难理解啊
为啥都说c++很难学难道是因为mfc么
我反正只是用c++给mcu
C++语法复杂, :: -> . C#只有 一个 .

acmilan3 年前 -2015-05-17 12:39769099 11阶
引用 金星凌日:
我记得C++ Primer里面就有一个例子。
另外,你这个赋值操作符似乎有点问题。
C++ Primer里确实有。。。在第421页
什么问题。。。有问题就是有问题,不要似乎

金星凌日3 年前 -2015-05-17 12:44769100 12阶
引用 acmilan:
C++ Primer里确实有。。。在第421页
什么问题。。。有问题就是有问题,不要似乎
你这个赋值操作符不能处理这样的情况:

MyClass a;
a=a;
我记得C++里是要考虑这种问题的。

acmilan3 年前 -2015-05-17 12:47769101 13阶
引用 金星凌日:
你这个赋值操作符不能处理这样的情况:

MyClass a;
a=a;我记得C++里是要考虑这种问题的。
嗯。。。多谢指教

acmilan3 年前 -2015-05-17 12:50769102 14阶
更改一处,多谢@金星凌日 提醒
MyClass &operator=(const MyClass& src) {
                                                            cout << "operator=" << endl;
    if (&src != this) { // 更改的地方
        Dispose();
        CopyFrom(src);
    }
    return *this;
}

acmilan3 年前 -2015-05-17 12:56769107 15阶
引用 acmilan:
嗯。。。多谢指教
C++我是看某人的blog学的,不是看C++ Primer学的,不是太扎实,标准库都不会用→_→

acmilan3 年前 -2015-05-17 12:59769109 16阶
引用 张静茹:
C++语法复杂, :: -> . C#只有 一个 .
你可以看看C++/CLI的语法,不忍直视→_→

acmilan3 年前 -2015-05-17 13:32769115 17阶
引用 1176764177:
98和11标准相差很大??
iar用的是那个标准?
我一般也就是用函数重载还有能随处定义变量这2点
mfc我没学一般不给pc写程序
要学貌似qt比较万金油吧
另外要是给MCU用的话,STL也是非常好用的

张静茹3 年前 -2015-05-17 14:09769118 18阶
引用 acmilan:
你可以看看C++/CLI的语法,不忍直视→_→
C++/CLI的语法一样很难

acmilan3 年前 -2015-05-17 14:15769120 19阶
引用 张静茹:
C++/CLI的语法一样很难
C++/CLI的语法十分混乱和难以理解。。。主要是要兼容C++语言所以搞得很复杂

金星凌日3 年前 -2015-05-17 20:30769179 20阶
引用 1176764177:
98和11标准相差很大??
iar用的是那个标准?
我一般也就是用函数重载还有能随处定义变量这2点
mfc我没学一般不给pc写程序
要学貌似qt比较万金油吧
实际上Qt使用的并不完全是C++。使用Qt的源代码要经过moc处理才可以交给C++编译器编译。

至于C++98和C++11的差别,一本介绍C++11新增内容的书就已经接近300页了。

11767641773 年前 -2015-05-18 06:31769225 21阶
引用 金星凌日:
实际上Qt使用的并不完全是C++。使用Qt的源代码要经过moc处理才可以交给C++编译器编译。

至于C++98和C++11的差别,一本介绍C++11新增内容的书就已经接近300页了。
只要向下兼容就好说。。

返回 软件综合
返回 本页顶部

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


nkc Development Server https://github.com/lovetheory/nkc2

科创研究院 (c)2005-2016

蜀ICP备11004945号-2 川公网安备51010802000058号