前面有一篇文章讲了指针与引用。并且还提到不能定义指向引用的指针(因为引用不是对象,没有实际的地址)。那么,能否定义指针的引用呢?答案是肯定的,因为指针本身就是一个对象。即然是对象,就能定义一个引用邦定该对象。先来看看指针的引用的用法:
以int类型为例如下:
void ReferencePointer() { int i = 5; // 变量i int* p = &i; // 指针p,指向变量i int*& pr = p; // 指针的引用,与p指向同一个变量i cout << i << " " << *p << " " << *pr << endl; i = 10; cout << i << " " << *p << " " << *pr << endl; cout << "addr: " << p << " " << pr << endl; // 指针的引用其它就是指针p的一个别名,和p有相同的地址 pr = NULL; // 因此也可以给指针赋空 cout << "addr: " << p << " " << pr << endl; }
结果:
5 5 5
10 10 10
addr: 0045FE50 0045FE50
addr: 00000000 00000000
在函数中,指针的引用作为参数可以起到很巧妙的作用。
假设有一个书的类Book,基定义如下:
struct Book
{
string isbn;
string name;
double price;
string author;
};
现在需要这样一个函数:有一个文件存放着一本书的相关信息(ISBN、书名、价格),现要从这个文件中读取信息并赋给Book的对象。
要定义这样一个函数,我们首先会想到的是有一个输入(文件的路径)和一个输出(Book的对象)。你可能会这样定义函数:
Book* GetBookFromFile(const string& filePath);
这种方式你必须在函数体内创建Book的对象(也就创建一个Book的内存空间),但函数体内创建的内存空间只在函数的作用域内有效,在函数体外是无效的,也就是说返回的指针将指向一个任意的值,这将是非常危险的。
如函数内:
在函数被调用后:
既然不行,您应该会想到另外一种定义方式如下:
Book GetBookFromFile(const string& filePath);
没错,这样定义确实可以,但需要在函数体内声明一个Book的对象,函数返回值的时候会进行一次对象的拷贝。这样增加了一个对象拷贝的过程,使效率降低。
Book GetBookFromFile(const string& filePath) { Book book; fstream fileInput(filePath); fileInput >> book.isbn >> book.name >> book.price; return book; }
您可能还会想到这种方式:
void GetBookFromFile(Book &book, const string& filePath);
没错,这确实可以解决上面的问题,不用再对对象进行拷贝。但新的问题又来了,上层调用这个函数时,如果要判断返回book对象是否正确获取了文件的信息得逐个地判断基属性是否空,如下代码。这无疑加重了上层调用的负担。
Book book;
GetBookFromFile(book, "E:\\book.txt");
if (!book.isbn.empty() && !book.name.empty() && book.price > 0)
{
// TO DO ...
}
当然,这有一种改进的方式,就是把返回值类型void改为bool,这样就可以通过返回的bool值确定函数是否成功调用。
针对上面的这个问题,如果返回的是Book的指针,直接判断返回的指针是否为NULL就可以。那么您可以有以下两种定义:
void GetBookFromFile(Book* book, const string& filePath);
void GetBookFromFile(Book*& book, const string& filePath);
当然,我是建议选择第二种方式,因为引用确保了传进来的指针有一个正确的值(引用必须在定义时被初始化)
定义如下:
void GetBookFromFile(Book* pBook, const string& filePath) { if (pBook == NULL) { return; } fstream fileInput(filePath); fileInput >> pBook->isbn >> pBook->name >> pBook->price; }
void GetBookFromFile(Book*& pBook, const string& filePath) { if (pBook == NULL) { return; } fstream fileInput(filePath); fileInput >> pBook->isbn >> pBook->name >> pBook->price; }
对这两个函数,调用方式都可以如下:
Book* pBook = new Book(); pBook->author = "SimileSunrise"; GetBookFromFile(pBook, "E:\\book.txt"); delete pBook;