Chinaunix首页 | 论坛 | 博客
  • 博客访问: 18681671
  • 博文数量: 7460
  • 博客积分: 10434
  • 博客等级: 上将
  • 技术积分: 78178
  • 用 户 组: 普通用户
  • 注册时间: 2008-03-02 22:54
文章分类

全部博文(7460)

文章存档

2011年(1)

2009年(669)

2008年(6790)

分类: 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                     // string.h for some
#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个函数!

阅读(268) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~