从运算符重载到指针悬挂

Mayuyu讲解指针悬挂之前,先来简单讲一下运算符重载,因为一般情况下我们是通过重载赋值运算符来解决指针

悬挂问题的。

 

我们知道,在C++中,编译时多态性是通过函数重载和运算符重载来实现的,也称为静态多态性。而运行时多态性是

通过继承和虚函数来实现的,也称为动态多态性。那么我们先来看看什么是运算符重载。

 

我们都知道对于像"+","-","*","/",这样的运算符来说,进行运算的对象必须是基本数据类型,比如int,long

等等。那么两个对象将无法进行这些操作,实际上通过运算符重载,同样可以进行这些操作,比如两个复数相加。

 

我们可以写出如下代码:

#include <iostream>
#include <string.h>
#include <stdio.h>

using namespace std;

class complex
{
    public:
    double real;
    double imag;
    complex(double real=0.0,double imag=0.0)
    {
        this->real = real;
        this->imag = imag;
    }
};

complex operator+(complex c1,complex c2)
{
    complex t;
    t.real = c1.real + c2.real;
    t.imag = c1.imag + c2.imag;
    return t;
}

//重载输出运算符"<<"
ostream &operator<<(ostream &out,complex &c)
{
    out<<c.real<<"+"<<c.imag<<"i"<<endl;
    return out;
}

int main()
{
    complex c1(1.0,2.0);
    complex c2(3.0,4.0);
    complex ans1,ans2;
    ans1 = c1 + c2;
    ans2 = operator+(c1,c2);
    cout<<ans1<<ans2<<endl;
    return 0;
}


 

在我们定义好重载运算符后,可以通过ans1 = c1 + c2或者ans2 = operator+(c1,c2)来使用它。似乎上面

的代码没有什么问题,但是前提是我们把数据成员都定义成共有的,所以在外界我们能直接用,如果你把它们设置

private类型的,你会发现编译不过,原因很简单:私有数据在类外部不能访问。我们学过友元函数,他本身不是

类的成员函数,但是我们却可以通过它来访问类内部的私有数据,相当于在类这个无法进入的黑匣子开了一个小孔,

这样就使得外界可以访问类内部的私有数据了。

 

我们把上面的代码修改一下:

#include <iostream>
#include <string.h>
#include <stdio.h>

using namespace std;

class complex
{
    private:
        double real;
        double imag;
    public:
        complex(double real=0.0,double imag=0.0)
        {
            this->real = real;
            this->imag = imag;
        }
        friend complex operator+(complex c1,complex c2);
        friend ostream &operator<<(ostream &out,complex &c);
};

complex operator+(complex c1,complex c2)
{
    complex t;
    t.real = c1.real + c2.real;
    t.imag = c1.imag + c2.imag;
    return t;
}

//重载输出运算符"<<"
ostream &operator<<(ostream &out,complex &c)
{
    out<<c.real<<"+"<<c.imag<<"i"<<endl;
    return out;
}

int main()
{
    complex c1(1.0,2.0);
    complex c2(3.0,4.0);
    complex ans1,ans2;
    ans1 = c1 + c2;
    ans2 = operator+(c1,c2);
    cout<<ans1<<ans2<<endl;
    return 0;
}

 

嗯,这样达到了目的。。。注意不能用友元函数重载的运算符有:=,(),[],->,所以要重载这四个运算符,必

须把它们当作成员函数。

 

现在我们来看两个重要的运算符++p和p++,它们是怎么重载的呢 ? 这个很重要。。。在C++中,编译器可以通过

在运算符函数参数表中是否插入关键字int来区分这两种方式。即:

 

classname operator++();        相当于++p

classname operator++(int);     相当于p++

 

比如:

#include <iostream>
#include <string.h>
#include <stdio.h>

using namespace std;

class X
{
    private:
        int x,y;
    public:
        X(int x,int y)
        {
            this->x = x;
            this->y = y;
        }
        X operator++();
        X operator++(int);
        friend ostream &operator<<(ostream &out,X &c);
};

X X::operator++()
{
    ++x;
    ++y;
    return *this;
}

X X::operator++(int)
{
    x++;
    y++;
    return *this;
}

//重载输出运算符"<<"
ostream &operator<<(ostream &out,X &c)
{
    out<<c.x<<" "<<c.y<<endl;
    return out;
}

int main()
{
    X c1(1,2);
    X c2(3,4);
    ++c1;
    c2++;
    cout<<c1<<c2<<endl;
    return 0;
}

 

到了这里,Mayuyu把运算符重载基本讲完了。。。

 

讲完运算符重载,我们来进一步看看指针悬挂问题。

#include <iostream>
#include <string.h>
#include <stdio.h>

using namespace std;

class String
{
    private:
        char *str;
    public:
        String(char *s)
        {
            str = new char[strlen(s) + 1];
            strcpy(str,s);
        }
        ~String()
        {
            delete str;
        }
        void Print()
        {
            cout<<str<<endl;
        }
};

int main()
{
    String p1("Mayuyu");
    {
       String p2("Hello!");
       p2 = p1;
       p2.Print();
    }
    p1.Print();
    return 0;
}

如上代码,我们知道对象之间的赋值其实就是引用,而不是重新开辟一块新的空间。也就是说在main()中执行语句

p2 = p1后,指针指向情况如下图:

 

 

也就是说,p1和p2指向同一块内存空间,而在主函数的{}中的代码在执行完毕后会调用p2的析构函数,也就是说

p1和p2共同指向的那块内存被释放了,那么将会出现指针p1指向不明确,p1变成了野指针。这样是极其危险的。

 

所以我们要解决这个问题,一个很明显的解决办法就是,在执行"="运算符时,让p1和p2各指向一个内存块,而这

两个内存块一个是另一个的复制品,这样就避免了上面的出错情况。当然实际上还有一个做法也是比较好的,方法

大致如下:

 

   对于同一个内存块,我们用一个count统计,有多少个指针指向它,加一个指针count++,释放一个count--,

   如果最后count = 1时,我们才真正释放这块内存,这样貌似比较麻烦,不在我们讨论范围内。

 

下面,我们只需要重载"=",在函数体内实现拷贝就行了。代码如下:

 

#include <iostream>
#include <string.h>
#include <stdio.h>

using namespace std;

class String
{
    private:
        char *str;
    public:
        String(char *s)
        {
            str = new char[strlen(s) + 1];
            strcpy(str,s);
        }
        ~String()
        {
            delete str;
        }
        void Print()
        {
            cout<<str<<endl;
        }
        String &operator=(const String &);
};

String &String::operator=(const String &p)
{
    if(this == &p) return *this;
    delete str;
    str = new char[strlen(p.str) + 1];
    strcpy(str,p.str);
    return *this;
}

int main()
{
    String p1("Mayuyu");
    {
       String p2("Hello!");
       p2 = p1;
       p2.Print();
    }
    p1.Print();
    return 0;
}


 

这样,就解决了指针悬挂问题。。。

 

Mayuyu在这里感谢广大网友的阅读,不要忘了评论哦!!!

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值