c++中的引用的使用原理以及使用实例 (3)

来源:互联网 发布:java解析json对象 编辑:程序博客网 时间:2024/05/22 04:38

写到这里已经写了很多了,一个下午吧。

问题弄好了我就想继续更改程序,是程序按照我的设想运行:

第一可以不用引用不?

可以用指针,不过相应的地方要改:

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 <iostream>
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;
    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>                    // 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
}

StringBad::StringBad()                // default constructor
{
    len = 4;
    str = new char[4];
    strcpy(str, "C++");               // default string
    num_strings++;
    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需要的,需要的是非指针型的。那么系统就又帮你构造一个隐式的复制函数。

非指针型的不可以用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)达到全部的要求:

最后结果就是按照我们的目的了!

最后就是全部用引用,这个是最好的方法了!

这样:

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;
}

最后说明一点,使用引用的时机。流操作符<<和>>、赋值操作符=的返回值、拷贝构造函数的参数、赋值操作符=的参数、其它情况都推荐使用引用。

这个也是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个函数!

原创粉丝点击