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

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

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

第一可以不用引用不?

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

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

你可能感兴趣的:(编程,C++,c,C#,OS)