分类: C/C++
2008-05-30 18:22:53
写到这里已经写了很多了,一个下午吧。
问题弄好了我就想继续更改程序,是程序按照我的设想运行:
第一可以不用引用不?
可以用指针,不过相应的地方要改:
StringBad::StringBad(const StringBad *st)
{
num_strings++;
len = st->len; // set size
str = new char[len + 1]; // allot storage
strcpy(str, st->str); // initialize pointer
// set object count
cout << num_strings << \": \\\"\" << str
<< \"\\\" object created\\n\"; // For Your Information
}
这个是显示构造函数。
改头文件,再改main中的传值,由于
void callme2(StringBad sb)
{
cout << \"String passed by value:\\n\";
cout << \" \\\"\" << sb << \"\\\"\\n\";
}
因为上面对复制构造函数使用的是指针,如果仍旧用传值,sb=headline2也就是sb=StringBad::StringBad(headline2),指针要求的是 sb=StringBad::StringBad(&headline2),也就是说这个复制构造函数跟没有一样,是问题简单化就这样吧,void callme2(StringBad sb)编程void callme2(StringBad &sb),用引用!
改过之后的main程序是:
// vegnews.cpp -- using new and delete with classes
// compile with strngbad.cpp
#include
using std::cout;
#include \"stringbad.h\"
void callme1(StringBad &); // pass by reference
void callme2(StringBad &); // pass by value
int main()
{
using std::endl;
StringBad headline1=StringBad::StringBad(\"Celery Stalks at Midnight\");
StringBad headline2(\"Lettuce Prey\");
StringBad sports(\"Spinach Leaves Bowl for Dollars\");
cout << \"headline1: \" << headline1 << endl;
cout << \"headline2: \" << headline2 << endl;
cout << \"sports: \" << sports << endl;
callme1(headline1);
cout << \"headline1: \" << headline1 << endl;
callme2(headline2);
cout << \"headline2: \" << headline2 << endl;[Page]
cout << \"Initialize one object to another:\\n\";
StringBad sailor =StringBad::StringBad(&sports);
cout << \"sailor: \" << sailor << endl;
cout << \"Assign one object to another:\\n\";
StringBad knot;
knot = headline1;
cout << \"knot: \" << knot << endl;
cout << \"End of main()\\n\";
return 0;
}
void callme1(StringBad & rsb)
{
cout << \"String passed by reference:\\n\";
cout << \" \\\"\" << rsb << \"\\\"\\n\";
}
void callme2(StringBad &sb)
{
cout << \"String passed by value:\\n\";
cout << \" \\\"\" << sb << \"\\\"\\n\";
}
另一个源文件是:
// strngbad.cpp -- StringBad class methods
#include
#include \"stringbad.h\"
//using std::cout;
using namespace std;
// initializing static class member
int StringBad::num_strings = 0;
// class methods
// construct StringBad from C string
StringBad::StringBad(const char * s)
{
len = strlen(s); // set size
str = new char[len + 1]; // allot storage
strcpy(str, s); // initialize pointer
num_strings++; // set object count
cout << num_strings << \": \\\"\" << str
<< \"\\\" object created\\n\"; // For Your Information
[NextPage]
}
StringBad::StringBad() // default constructor
{
len = 4;
str = new char[4];
strcpy(str, \"C++\"); // default string
num_strings++;[Page]
cout << num_strings << \": \\\"\" << str
<< \"\\\" default object created\\n\"; // FYI
}
StringBad::~StringBad() // necessary destructor
{
cout << \"\\\"\" << str << \"\\\" object deleted, \"; // FYI
--num_strings; // required
cout << num_strings << \" left\\n\"; // FYI
delete [] str; // required
}
std::ostream & operator<<(std::ostream & os, const StringBad & st)
{
os << st.str;
return os;
}
StringBad::StringBad(const StringBad *st)
{
num_strings++;
len = st->len; // set size
str = new char[len + 1]; // allot storage
strcpy(str, st->str); // initialize pointer
// set object count
cout << num_strings << \": \\\"\" << str
<< \"\\\" object created\\n\"; // For Your Information
}
StringBad & StringBad::operator=(const StringBad st)
{
if (this == &st)
return *this;
delete [] str;
len = st.len;
str = new char[len + 1];
strcpy(str, st.str);
return *this;
}
程序执行的时候没有问题,在不给StringBad & StringBad::operator=(const StringBad st)函数的参数使用引用的时候程序结果就出现了问题,在最后的析构的时候乱码了!
原因出自下面的 StringBad knot; knot = headline1;第一步正确,使用默认的构造函数,第二步就不对了,单步就可以晓得,程序还是调用了StringBad & StringBad::operator=(const StringBad st),即使调用了这个函数也还是要调用复制构造函数的,我步知道为什么,就是这么一回事,上面定义的是指针类型的复制构造函数,不是knot = headline1需要的,需要的是非指针型的。那么系统就又帮你构造一个隐式的复制函数。[Page]
非指针型的不可以用StringBad::StringBad(const StringBad st),调试就晓得出错了,那么就只能用引用了。
这样:
StringBad::StringBad(const StringBad &st)
{
num_strings++;
len = st.len; // set size
str = new char[len + 1]; // allot storage
strcpy(str, st.str); // initialize pointer
// set object count
cout << num_strings << \": \\\"\" << str
<< \"\\\" object created\\n\"; // For Your Information
}
StringBad & StringBad::operator=(const StringBad st)
{
if (this == &st)
return *this;
delete [] str;
len = st.len;
str = new char[len + 1];
strcpy(str, st.str);
return *this;
}
或者就这样,把StringBad & StringBad::operator=(const StringBad st)改成使用引用参数:
StringBad & StringBad::operator=(const StringBad &st),这样在knot = headline1的时候就不用再调用StringBad::StringBad(const StringBad &st),可以直接用StringBad & StringBad::operator=(const StringBad &st)达到全部的要求:
[NextPage]
最后结果就是按照我们的目的了!
最后就是全部用引用,这个是最好的方法了!
这样:
StringBad::StringBad(const StringBad &st)
{
num_strings++;
len = st.len; // set size
str = new char[len + 1]; // allot storage
strcpy(str, st.str); // initialize pointer
// set object count
cout << num_strings << \": \\\"\" << str
<< \"\\\" object created\\n\"; // For Your Information[Page]
}
StringBad & StringBad::operator=(const StringBad & st)
{
if (this == &st)
return *this;
delete [] str;
len = st.len;
str = new char[len + 1];
strcpy(str, st.str);
return *this;
}
最后说明一点,使用引用的时机。流操作符<<和>>、赋值操作符=的返回值、拷贝构造函数的参数、赋值操作符=的参数、其它情况都推荐使用引用。
这个也是efficient c++说明确说明了的一点!
最后说明一点,就是显式复制构造函数跟隐式复制构造函数最大的区别,就是前者由程序员自己定义,一般都会编写成深度复制,而后者就是浅复制。
何谓深度复制?深度复制就是将要被复制的对象,生成一个副本,然后将副本的地址以及数据全部复制,通过strcpy以及strncpy这两个函数实现就像上面的程序:
len = st.len; // set size
str = new char[len + 1]; // allot storage
strcpy(str, st.str); // initialize pointer
而隐式的浅复制就是系统自己生成一个函数然后把对象复制给目标,比如有两个同类对象,跟上面的定义一样,有boo=foo,则是直接把boo.len=foo.len,再boo.str=foo.str。那么可以知道浅复制就是仅仅通过直接的地址赋予而达到给值 的目的,但是隐式函数使用之后就自己销毁自己,也就是析构了,把boo析构了,那么foo的地址还存在?明显在访问foo的时候就有异常了!
因此:StringBad knot=headline1;这种情况要给出相对应的正确的显示复制构造函数,而StringBad knot; knot = headline1;这种情况就更加要给出显示的函数了,而且还要给出默认构造函数,最后还要给出赋值操作符的函数,因为第一句调用默认构造函数,第二句调用赋值操作符,而同时也会调用相应的复制构造函数,因此这个情况要给出3个函数!