类中有指针成员变量时的一些注意事项
2015-04-15 21:29
253 查看
知识真的是知道的越多,不知道到的越多。本来只是想在自己写的string类中加个记录对象的静态成员变量,刚开始遇到了计数结果为负值的情况,后来知道了有复制构造函数这么一说。有因为类中声明了一个str的指针变量,导致了一些内存问题,于是迫使自己重载了构造函数,析构函数,甚至还知道并重载了赋值运算符。后来,在网上系统的查了下,原来一个类在创建时候,编译器会自动生成默认构造函数(若没有),复制构造函数(若没有),默认析构函数(若没有),赋值运算符(若没有),取地址运算符(若没有)。以下列出了自己最终版本的string类,为了方便对照查看,将说明写在了代码的注释里。
最终的运行结果如下:
总结:测试程序中用几种不同的方式创建了mystring 对象,使用num对其进行计数,并打印出了构造函数等调用的时机,大家可以对照查看,或者自己写代码测试。本文主要是想说明在对有指针变量的类中,进行复制赋值操作时,要注意深度复制赋值。顺带着介绍了转换函数(将类转换成其他类型变量,或者将其他类型变量转换成类变量)的语法。其中注释中都有详细介绍在此就不再赘述。
由于本人才疏学浅,若有错误,欢迎指正,不胜感激。
//mystring.h #ifndef MYSTRING_H_ #define MYSTRING_H_ #include <iostream> using std::ostream; class mystring { private: char* str; int len; static int num;//对存在的对象进行计数 public: mystring();//默认构造函数 mystring(char* c);//带参构造函数 mystring(const mystring& mystr);//复制构造函数 ~mystring();//析构函数 char& operator[](int i);//重载[]运算符----非const对象调用 const char& operator[](int i) const;//重载[]运算符----const对象调用,函数重载区分const与非const对象 mystring& operator=(mystring& mystr);//重载赋值运算符 friend ostream& operator<<(ostream& os,const mystring& mystr); operator char*(); }; #endif
//mystring.cpp #include <string> #include <iostream> #include "mystring.h" using std::cout; using std::endl; int mystring::num = 0;//初始化静态变量,不用加static,但需要加类型 mystring::mystring()//默认构造函数,生成空串 { len = 0; // str = new char[1];//对应析构函数的delete[] // str[0] = '\0'; str = 0;//空指针同样也用delete[]释放 num++; cout<<"调用默认构造函数,第"<<num<<"个对象"<<endl; } mystring::mystring(char* c) { len = strlen(c); str = new char[len + 1]; strcpy(str,c); num++; cout<<str<<":调用带参数构造函数,第"<<num<<"个对象"<<endl; } mystring::mystring(const mystring& mystr)//对使用复制构造函数创建的对象进行深度复制,否则,比方说创建的临时对象析构时会会把内存中的内容释放,指针指向的内容将不复存在 { len = mystr.len; str = new char[len + 1]; strcpy(str,mystr.str); num++; cout<<str<<":调用复制构造函数,第"<<num<<"个对象"<<endl; } mystring::~mystring() { num--; if(str == 0)//空指针 cout<<"空对象调用析构函数,剩余"<<num<<"个对象"<<endl; else cout<<str<<":调用析构函数,剩余"<<num<<"个对象"<<endl; delete[] str;//释放对象str占用的内存 } mystring& mystring::operator =(mystring& mystr)//默认赋值运算符是浅度复制,只是将指针复制过去,指向的内容并没有复制。这并不符合赋值的初衷,而且一处的修改会影响其他的对象的str { if(this == &mystr) return *this; delete[] str; len = mystr.len; str = new char[len + 1]; strcpy(str,mystr.str); return *this;//返回对象引用可进行连续赋值 } char& mystring::operator [](int i)//非const对象 { return str[i];//其本质是返回一个地址,使用其对对象数据进行修改 } const char& mystring::operator [](int i) const//const对象调用,也可返回非const引用,但可通过引用对const对象进行修改,不科学 { return str[i];//若不返回const,可利用其返回的地址对const对象进行修改,类中的数据,即使是私有成员也可以通过地址进行访问或者修改 } ostream& operator<<(ostream& os,const mystring& mystr) //必须返回ostream对象的引用,因为没有公有的复制构造函数(不能创建临时对象) { os<<mystr.str<<"是长度为"<<mystr.len<<"的字符串"; return os;//使连续输出成为可能, } mystring::operator char*()//将类转化为其他类型 { return str; }
//test.cpp #include <iostream> #include "mystring.h" using namespace std; int main() { mystring str1; mystring str2("hehe"); const mystring str3("const hehe"); str2[1] = 'a'; str2[3] = 'a';//调用非const重载[],修改str2 //str3[1] = 'a';//报错,返回类型为const不可修改 mystring* pStr = new mystring(str2);//用str2初始化一个新的对象指针,区别于mystring* pStr = &str2 str1 = *pStr;//取pStr值然后赋值给str1,调用重载=运算符,new生成的对象,必须用delete调用析构函数释放内存 delete pStr;//析构pStr cout<<str3<<"!!!"<<endl; mystring s = "???";//使用的隐式的类型转换,单参数的构造函数的功能,与s = mystring("???")等效。 cout<<s<<"!!!"<<endl; char* p = str2;//使用隐式类型转换,与char* p =char*(str2)等效 cout<<p<<endl; return 0; }
最终的运行结果如下:
总结:测试程序中用几种不同的方式创建了mystring 对象,使用num对其进行计数,并打印出了构造函数等调用的时机,大家可以对照查看,或者自己写代码测试。本文主要是想说明在对有指针变量的类中,进行复制赋值操作时,要注意深度复制赋值。顺带着介绍了转换函数(将类转换成其他类型变量,或者将其他类型变量转换成类变量)的语法。其中注释中都有详细介绍在此就不再赘述。
由于本人才疏学浅,若有错误,欢迎指正,不胜感激。
相关文章推荐
- [Boolan] C++第一周(创建一个不带指针成员变量的类)[注意事项]
- C++ 构造函数使用 ":成员变量(形参)" 的形式给类里面成员变量赋值,如果成员变量和形参是指针,那么需要注意的事项
- [Boolan] C++第二周(创建一个带指针成员变量的类)[注意事项]
- 类成员变量中存在引用,const,和指针类型时需要注意的事项
- 关于指针的一些注意事项
- 指针的一些注意事项
- 结构体指针变量使用时的注意事项
- c++中引用变量的注意事项,和指针的区别
- 你不可不知的static(3)-注意事项、区别成员变量、静态main
- java语言基础(26)——面向对象(类的设计及成员变量定义注意事项)
- 笔记3:指针和使用时一些注意事项
- C++ 与“类”有关的注意事项总结(五):指向类成员的指针
- struts使用总结一:慎用actionServlet成员变量,actionServlet生命周期,actionForm生命周期,struts上传注意事项
- static 关键字 成员变量和静态变量的区别 静态使用的注意事项 静态代码块 构造代码块
- c++全局变量使用中的一些注意事项
- 黑马程序员_环境变量的一些注意事项
- 有指针成员变量,要注意莫要MLK了
- 12-面向对象(static关键字-成员变量和静态变量的区别-数据共享 13-面向对象(static关键字-注意事项) 14-面向对象(static关键字-main函数解析 15-面向对象(stat
- 局部变量作用域,方法编写的注意事项:或者说是一些原则
- 指针的一些注意事项