从运算符重载到指针悬挂
2014-03-31 15:59
281 查看
在Mayuyu讲解指针悬挂之前,先来简单讲一下运算符重载,因为一般情况下我们是通过重载赋值运算符来解决指针
悬挂问题的。
我们知道,在C++中,编译时多态性是通过函数重载和运算符重载来实现的,也称为静态多态性。而运行时多态性是
通过继承和虚函数来实现的,也称为动态多态性。那么我们先来看看什么是运算符重载。
我们都知道对于像"+","-","*","/",这样的运算符来说,进行运算的对象必须是基本数据类型,比如int,long
等等。那么两个对象将无法进行这些操作,实际上通过运算符重载,同样可以进行这些操作,比如两个复数相加。
我们可以写出如下代码:
在我们定义好重载运算符后,可以通过ans1 = c1 + c2或者ans2 = operator+(c1,c2)来使用它。似乎上面
的代码没有什么问题,但是前提是我们把数据成员都定义成共有的,所以在外界我们能直接用,如果你把它们设置
private类型的,你会发现编译不过,原因很简单:私有数据在类外部不能访问。我们学过友元函数,他本身不是
类的成员函数,但是我们却可以通过它来访问类内部的私有数据,相当于在类这个无法进入的黑匣子开了一个小孔,
这样就使得外界可以访问类内部的私有数据了。
我们把上面的代码修改一下:
嗯,这样达到了目的。。。注意不能用友元函数重载的运算符有:=,(),[],->,所以要重载这四个运算符,必
须把它们当作成员函数。
现在我们来看两个重要的运算符++p和p++,它们是怎么重载的呢 ? 这个很重要。。。在C++中,编译器可以通过
在运算符函数参数表中是否插入关键字int来区分这两种方式。即:
classname operator++(); 相当于++p
classname operator++(int); 相当于p++
比如:
到了这里,Mayuyu把运算符重载基本讲完了。。。
讲完运算符重载,我们来进一步看看指针悬挂问题。
如上代码,我们知道对象之间的赋值其实就是引用,而不是重新开辟一块新的空间。也就是说在main()中执行语句
p2 = p1后,指针指向情况如下图:
也就是说,p1和p2指向同一块内存空间,而在主函数的{}中的代码在执行完毕后会调用p2的析构函数,也就是说
p1和p2共同指向的那块内存被释放了,那么将会出现指针p1指向不明确,p1变成了野指针。这样是极其危险的。
所以我们要解决这个问题,一个很明显的解决办法就是,在执行"="运算符时,让p1和p2各指向一个内存块,而这
两个内存块一个是另一个的复制品,这样就避免了上面的出错情况。当然实际上还有一个做法也是比较好的,方法
大致如下:
对于同一个内存块,我们用一个count统计,有多少个指针指向它,加一个指针count++,释放一个count--,
如果最后count = 1时,我们才真正释放这块内存,这样貌似比较麻烦,不在我们讨论范围内。
下面,我们只需要重载"=",在函数体内实现拷贝就行了。代码如下:
这样,就解决了指针悬挂问题。。。
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在这里感谢广大网友的阅读,不要忘了评论哦!!!
相关文章推荐
- 使用深拷贝解决指针悬挂问题(“=”运算符重载)
- 运算符重载之->为下标成员运算符,而不是指针
- 小错误变成大错误 不知道该怎么改了 应该是指针悬挂问题吧
- 悬挂指针与boost::weak_ptr
- 指针悬挂~实例解释
- *运算符,->运算符重载与智能指针
- 指针悬挂(转)
- C++中指针悬挂问题的产生以及如何避免
- 防止指针悬挂的方法
- Item 20: 使用std::weak_ptr替换会造成指针悬挂的类std::shared_ptr指针
- 什么是内存泄漏?野指针?悬挂指针?空指针异常?
- 指针悬挂
- C++ 指针悬挂和赋值操作符的重载,拷贝构造函数实现
- C++_指针悬挂和赋值操作符的重载
- C++指针悬挂(赋值运算符重载)
- C++ 指针悬挂和赋值操作符的重载,拷贝构造函数实现
- 内存共享问题,指针悬挂问题及其解决方法
- Dangling Pointers----悬挂指针
- MOOC清华《面向对象程序设计》第8章:悬挂指针实验
- C/C++:智能指针原理(运算符重载)、使用auto_ptr<A>