引用与类对象
先看个引用与类对象的demo:
#include <iostream>
#include <string>
using namespace std;
string version1(const string & s1, const string & s2);
const string & version2(string & s1, const string & s2);
const string & version3(string & s1, const string & s2);
int main()
{
string input;
string copy;
string result;
cout << "Enter a string : " << endl;
getline(cin, input);
copy = input;
cout << "input : " << input << endl;
result = version1(input, "***");
cout << "result : " << result << endl;
cout << "Your original string input : " << input << endl;
result = version2(input, "###");
cout << "result : " << result << endl;
cout << "Your original string input : " << input << endl;
cout << "Reset original string " << endl;
input = copy;
// 这里会出问题, 因为version3中返回的是一个局部变量temp的引用
// 而temp在version3执行完毕后就会不存在, 因此result去获取引用的时候就会挂掉
result = version3(input, "@@@");
cout << "result : " << result << endl;
cout << "Your original string input : " << input << endl;
return 0;
}
string version1(const string & s1, const string & s2)
{
string temp;
temp = s2 + s1 + s2;
// 返回的是temp的副本, 按值返回
return temp;
}
const string & version2(string & s1, const string & s2)
{
s1 = s2 + s1 + s2;
// 返回的是s1的引用, 安全的
return s1;
}
const string & version3(string & s1, const string & s2)
{
string temp;
temp = s2 + s1 + s2;
// 返回的是temp的引用, 但是这个是不安全的, 因为
// temp是局部变量, 当version3执行完毕后temp就不存在了
return temp;
}
程序运行结果:
需要注意的地方都在注释中写明了, 只需要额外注意一点就是version3这个函数, 由于返回的是局部变量temp的引用, 而temp在version3执行完毕的时候会被回收, 所以version3可能会造成程序崩溃.
引用与对象, 继承
看一个demo
// 对象, 继承, 引用
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
void file_it(ostream & os, double fo, const double fe[], int n);
const int LIMIT = 5;
int main()
{
ofstream fout;
const char* fn = "ep-data.txt";
fout.open(fn);
if(!fout.is_open())
{
cout << "can not open " << fn << " bye " << endl;
exit(EXIT_FAILURE);
}
double objective;
cout << "Enter the focal length of your telescope objective in mm :";
cin >> objective;
double eps[LIMIT];
cout << "Enter the local lengths , in mm of " << LIMIT << " eyepieces:" << endl;
for(int i = 0; i < LIMIT; i++)
{
cout << "Eyepiece #" << i + 1 << endl;
cin >> eps[i];
}
file_it(fout, objective, eps, LIMIT);
file_it(cout, objective, eps, LIMIT);
cout << "Done" << endl;
return 0;
}
void file_it(ostream & os, double fo, const double fe[], int n)
{
ios_base::fmtflags initial;
// 将对象置于使用定点表示法的模式
initial = os.setf(ios_base::fixed);
// 指定显示多少位小数
os.precision(0);
os << "Focal length of objective : " << fo << " mm " << endl;
// 将对象置于显示小数点的模式
os.setf(ios::showpoint);
os.precision(1);
// 设置下一次输出操作使用的字段宽度
// 这种设置只在显示下一个值时有效, 然后将恢复到默认设置
// 默认的字段宽度为零, 这意味着刚好能容纳下要显示的内容.
os.width(12);
os << "f.1.eyepieces";
os.width(22);
os << "magnification" << endl;
for(int i = 0; i < n; i++)
{
os.width(12);
os << fe[i];
os.width(22);
// 强制转换为int值
os << int (fo / fe[i] + 0.5) << endl;
}
// 返回调用它之前有效的所有格式化设置.
os.setf(initial);
}
程序运行结果为:
对应的输出到文件中的截图:
函数void file_it(ostream & os, double fo, const double fe[], int n);接收的是ostream 的引用对象, 而ofstream是ostream的子类, 因此函数也能接收fout和cout.
demo中关于现阶段没用到的几个方法都做了注释,
方法setf()可以让我们更能够设置各种格式化状态. 例如: 方法调用setf(ios_base::fixed)将对象置于使用定点表示法的模式; setf(ios_base::showpoint)将对象置于显示小数点的模式, 即使小数部分为零. 方法precision()指定显示多少位小数(假定对象处于定点模式下). 所有这些设置都将一直保持不变, 直到再次调用相应的方法重新设置它们.
这个例子只要看懂为什么ostream & 能接收fout和cout就可, 关于格式化的问题可以慢慢理解
怎么使用引用
何时使用引用参数:
1.程序需要修改调用函数中的数据对象
2.通过传递引用而不是整个数据对象, 可以提高程序的运行速度.
引用, 指针, 值传递的使用规则:
对于使用传递的值, 而不做修改的函数:
1.如果数据对象很小, 如内置数据类型或小型结构, 则按值传递
2.如果数据对象是数组, 则使用指针, 因为这是唯一的选择, 并将指针声明为指向const的指针
3.如果数据对象是较大的结构, 则使用const指针, 或const引用, 以提高程序的效率, 这样可以节省复制结构所需的时间和空间.
4.如果数据对象是类对象,则使用const引用. 传递类对象参数的标准方式是按引用传递.
如果修改调用函数中数据的函数:
1.如果数据对象是内置数据类型, 则使用指针.
2.如果数据对象是数组, 则只能使用指针
3.如果数据对象是结构, 则使用引用或指针
4.如果数据对象是类对象, 则使用引用.