写 c++ 程序的时候要特别小心这种函数参数的传递。稍不注意就会出现问题。
下面看一段代码并思考,为什么这里的 double grade(double, double, const std::vector<double>&);
的第三个参数是std::vector<double>&
,而 double median(std::vector<double>);
的参数是 std::vector<double>
.
#include <iostream>
#include <sstream>
#include <iomanip>
#include <ios>
#include <vector>
#include <algorithm>
#include <stdexcept>
using std::endl;
double grade(double, double, double);
double grade(double, double, const std::vector<double>&);
double median(std::vector<double>);
int main()
{
std::cout << "Please enter your first name." << endl;
std::string name{};
std::cin >> name;
std::cout << "Hello " << name << " !" << endl;
std::cout << "Please enter your middle and final exam grades: ";
double middle = 0, final = 0;
std::cin >> middle >> final;
std::cout << "Enter all your homework grades"
"followed by end-of-file: ";
std::vector<double> homework;
double x;
while (std::cin >> x)
{
homework.push_back(x);
}
printf("homework is %p\n", &homework);
std::streamsize prec = std::cout.precision();
std::cout << "Your final grade is " << std::setprecision(3)
<< grade(middle, final, homework)
<< std::setprecision(prec) << std::endl;
return 0;
}
double grade(double median, double final, const std::vector<double>& hw) {
printf("hw is %p\n", &hw);
// 在 main() 里面调用这个函数的时候,传入的是 main 中的 homework 的 引用,并不是对其的一个复制拷贝,
// 所以,这里的 hw 就是 main 里面的 homework,这里没毛病。
double mm = ::median(hw);
double rg = grade(median, final,mm);
return rg;
}
double median(std::vector<double> vec) {
// median 是被 grade(double,double,vector)调用的,这个 vec 是对其传入的 hw 的一个拷贝,也就是说,这个 vec 与 hw 是两个不同的对象。
// 另外 hw 是 const 没事,t它只是赋值给vec,不会让vec也变成 const
printf("vec is %p\n", &vec);
std::vector<double>::size_type len = vec.size();
if (len == 0)
{
throw std::domain_error("vector is empty...");
}
std::sort(vec.begin(), vec.end());
int mp = len / 2;
double number;
if (len % 2 == 0)
{
// even length
number = 0.5 * (vec[mp] + vec[mp - 1]);
}
else {
// odd length
number = vec[mp];
}
return number;
}
double grade(double middle, double final, double homework) {
return 0.2 * middle + 0.4 * final + 0.4 * homework;
}
首先函数的调用栈是 main() -> grade() -> median() . 函数实参是在main() 里面创建的 homework
对象。在调用 grade
函数的时候,这里传入的是一个常量引用,所以这里不会去创建对象,并且保证grade
函数不会去修改main
中创建的homework
对象,而 median()
函数的参数类型就是std::vector<double>
,所以这里会进行一个拷贝赋值,也就是创建了一个新的对象。所以在 median
里面去进行排序,不会影响到原来的homework
对象,因为 hw
与 vec
是两个不同的对象。
看一下输出就明白了:
homework is 0000007EE0F7F7A8
hw is 0000007EE0F7F7A8
vec is 0000007EE0F7F688
可以看到 homework
与 hw
是同一个地址,而 vec
是一个新的地址。