这段时间在学习C++,虽然以前学过,但学校里学的和真正的用起来还是有差距的,写程序的时候发现自己知道的还是太少了,在学习的过程中,发现了一些问题,在这里总结一下,以备以后查看。同时也供大家拍砖。。。
环境:ubuntu11.10
编译器:g++4.6.1
我们先定义一个类把:
class String
{
private:
intm_len;
char*m_str; //定义了3个私有成员变量 ,这里是个指针
staticint num;
public:
String();//构造函数
~String();//析够函数
friendostream &operator<<(ostream &,String &); //重载<<
String(constString &); //拷贝函数 拷贝函数的定义是(const String &) 不能是//(String &),一定不能少了const,少了会报错
String(constchar*); //普通类型—>类类型转换
String&operator=(const char *);//实现 String t; t="chenyu" 这样的行为
String&operator=(const String &);//实现String t; t=t2;这样的行为
};
然后我们实现这些接口函数:
int String::num=0;
String::String() //自定义构造函数
{
m_len=strlen("chenyu")+1;
m_str= new char[m_len];
strncpy(m_str,"chenyu",m_len);
num++;
}
String::~String() //析够函数
{
num--;
cout<<"destory"<<m_str<< " left:" << num<< endl;
delete[] m_str;
}
ostream &operator<<(ostream&os,String &str) //重载<<
{
os<<"str.m_len:"<<str.m_len<<endl
<<"str.m_str:"<<str.m_str<<endl;
returnos;
}
String::String(const String &str) //拷贝函数
{ m_len=str.m_len;
m_str=newchar[m_len];
strncpy(m_str,str.m_str,m_len);
num++;
}
String::String(const char *str) //类型转换构造函数,
{
m_len=strlen(str)+1;
m_str=new char [m_len];
strncpy(m_str,str,m_len);
num++;
}
String &String::operator=(const char*str)//赋值重载,
{
if(NULL==str)
{
cout<<"=err"<<endl;
return(*this);
}
deletem_str;
m_len=strlen(str)+1;
m_str= new char[m_len];
strncpy(m_str,str,m_len);
return(*this);
}
String &String::operator=(const String&str) //赋值重载,
{
if(&str==this) //这里要加一个入口检查,如果出现 string t1; t1=t1 ;这样的行为,会把t1的 m_str 给delete ,后面的赋值就会出现问题
{
return(*this);
}
deletem_str;
m_len=str.m_len;
m_str= new char[m_len];
strncpy(m_str,str.m_str,m_len);
return(*this);
}
然后下面调用函数(张老师说的专业用语,^_^):
int main()
{
Stringstr1;
cout<<"str1:"<<str1<<endl;
Stringstr2(str1); //等价于String str2=str1;
cout<<"str2:"<<str2<<endl;
Stringstr3=str1; //等价于String str3(str1); 这个不需要对=重载 是初始化
cout<<"str3:"<<str3<<endl;
Stringstr4 = "huhu"; // 等价于String str4("huhu");
cout<<"str4:"<<str4<<endl;
Stringstr5("huhu"); // 等价于String str5="huhu";
cout<<"str5:"<<str5<<endl;
Stringstr6;
cout<<"str6:"<<str6<<endl;
str6="xiejing";
cout<<"str6:"<<str6<<endl;
Stringstr7;
str7=str6; //这个要对=重载 是赋值
cout<<"str7:"<<str7<<endl;
Stringstr8("xixihaha");
cout<<"str8:"<<str8<<endl;
Stringstr9;
cout<<"str9:"<<str9<<endl;
str8=str8;
cout<<"str8:"<<str8<<endl;
return0;
}
从对这个简单程序的编写,遇到了一些问题,就是一些定义方式的理解。
1.对于上面的类String ,我们可以定义一个对象str1,如:
String str1;
输出:
cout<<"str1:"<<str1<<endl;
可以看到里面预定义构造函数对其的初始化内容。
2.我们还可这样定义:
String str2(str1);
这种定义实质上是等价于Stringstr2=str1;的,在这里我们就要调用拷贝构造函数了,大家都知道如果我们不自己定义拷贝构造函数,系统会调用默认拷贝构造函数,默认拷贝构造函数是一种浅拷贝,是一种值到值的复制,没有牵扯到空间的分配。可是在这个程序中,在我们的对象里,我定义了一个指针,在定义对象的时候系统会用new给每个对象分配空间,对于Stringstr2(str1);这个语句来说,如果按照系统的浅拷贝方式的话,str1和str2的m_str指针都会指向同一个存储空间,如下图:(这里图贴补上去,好理解)
好了,下面在说一个问题,当一个对象的生命周期结束之后,系统会调用析构函数去做一些处理,对于String str2=str1,我定义了一个析构函数,里面有一个delete,它使对象放弃对new分配的空间的使用权。当这两个对象的生命周期结束之后,会调用这个析构函数,对于str1和str2来说,它们的m_str指向同一个存储空间,这样结束后,会对这个存储空间delete两次,所以会出错。那么如何处理String str2=str1呢?对于前面的这个问题,我们可以给str2分配一个独立的空间,这样当析构时,就不会出错了,即定义个深拷贝构造函数:
String::String(const String &str) //拷贝函数
{
m_len=str.m_len;
m_str=newchar[m_len];
strncpy(m_str,str.m_str,m_len);
num++;
}
定义的时候,还要注意,参数的const关键字不能省略,不然会出错的。
3. 对于这种形式,我们可以做一下对比,
(1) Stringstr2=str1
(2) String str2;str2=str1
这两种表达意义是不一样的对于(1)来说,我们要调用深拷贝函数,但对于(2)来说,我们要调用对“=”的重载。
即代码中的:
String str7;
str7=str6;
对“=”的重载
String&String::operator=(const String &str)
{
if(&str==this) //这里要加一个入口检查,如果出现 string t1; t1=t1 ;这样的行//为,会把t1的 m_str 给delete
{
return (*this);
}
delete m_str;
m_len=str.m_len;
m_str = new char[m_len];
strncpy(m_str,str.m_str,m_len);
return (*this);
}
4. 在代码中可以看到,还有这种形式:
String str4 ="huhu";
它等价于Stringstr4("huhu");
这相当于一种类型的转换,即先把“huhu”转换为一个临时对象,然后再赋值给str4,这样的话我们要调用类型转换构造函数,即:
String::String(constchar *str) //类型转换构造函数,
{
m_len=strlen(str)+1;
m_str= new char [m_len];
strncpy(m_str,str,m_len);
num++;
}
5、在代码中还可以看到这种形式:
String str6;
str6="xiejing";
我们再和上面的对比下:
(1)
String str6;
str6="xiejing";
(2)String str4 = "huhu";
对于(2)来说,这样使用,它调用的是类型转换函数,但对于(1)来说就不是了,它调用的是:对“=”的重载函数
String&String::operator=(const char *str)//赋值重载,
{
if(NULL==str)
{
cout<<"=err"<<endl;
return (*this);
}
delete m_str;
m_len=strlen(str)+1;
m_str = new char[m_len];
strncpy(m_str,str,m_len);
return (*this);
}
总结起来就是一下四种形式,对于不同的情况,要调用不同的函数:
string str1;
(1)string str2=str1; //--àstringstr2(str1)
(2)stringstr3;
str3=str1;
(3)stringstr4=”huhuhu”; //--àstring str4(“huhuhu”)
(4)stringstr5;
str5=”huhuhu”;
本人菜鸟级别的,哪里不对的地方,欢迎拍砖。。。。。