问题起源:
直接将Sales_data(std::istream&is)构造函数移动到类内时,编译器报错
猜想:
1.可能是因为类构造函数内使用了read函数,而read函数形参为类对象,即因果关系颠倒
导致read函数无法被正常调用
验证过程:
第一次尝试:将类外构造函数定义从源文件移动到头文件内,且在read函数声明之前
结果:编译器报错
第二次尝试:将类外构造函数定义从源文件移动到头文件内,且在read函数声明之后
结果:编译成功
std::istream& read(std::istream& is, Sales_data& d);
Sales_data::Sales_data(std::istream& is)
{
read(is, *this);
}
这两次尝试对比我们可以知道:类外构造函数时,由于函数内部使用了read函数,所以定义构造函数时,需要在read函数声明之后(即在源文件中定义(read声明在头文件),或者在头文件且在read声明之后定义)
因此,如果要将类外构造函数在类的内部定义,则read函数声明一定要在该构造函数之前
第三次尝试:
3.1:将read声明在类内,构造函数之前(对应#1位置)
3.2:将read声明在类外,Sales_data之前(对应#2位置)
(注意:下图中,#1与#2代码不同时存在,每次仅存在一种)
结果:均编译失败
原因:
3.1:在类内的声明中, 构造函数优先声明,其次才按顺序声明,因此无论read放在类内哪个位置,声明均在构造函数之后
3.2:在类外的声明中,read确实声明比构造函数早,但read形参有Sales_data,此时Sales_data声明却比read晚,因此遇到了新的同类问题
std::istream& read(std::istream& is, Sales_data& d);//#1
struct Sales_data
{
std::string bookno;
unsigned units_sold = 0;
double revenue = 0.0;
Sales_data() = default;
Sales_data(const std::string s) :bookno(s) {}
Sales_data(const std::string s, const unsigned sd, const double r) :bookno(s), units_sold(sd), revenue(r) {}
std::istream& read(std::istream& is, Sales_data& d);//#2
Sales_data(std::istream& is);
Sales_data& combine(Sales_data& d);
std::string isbn()const
{
return bookno;
}
};
Sales_data::Sales_data(std::istream& is)
{
read(is, *this);
}
第四次尝试:
把类的声明和read函数的声明放置在构造函数前
结果:编译成功
struct Sales_data;
std::istream& read(std::istream& is, Sales_data& d);
struct Sales_data
{
std::string bookno;
unsigned units_sold = 0;
double revenue = 0.0;
Sales_data() = default;
Sales_data(const std::string s) :bookno(s) {}
Sales_data(const std::string s, const unsigned sd, const double r) :bookno(s), units_sold(sd), revenue(r) {}
Sales_data(std::istream& is)
{
read(is, *this);
}
Sales_data& combine(Sales_data& d);
std::string isbn()const
{
return bookno;
}
};
以下是能正常运行的原程序文件:
头文件:
//头文件"Sales_data.h"
#ifndef SALESDATA
#define SALESDATA
#include<string>
struct Sales_data
{
std::string bookno;
unsigned units_sold=0;
double revenue =0.0;
Sales_data() = default;
Sales_data(const std::string s):bookno(s) {}
Sales_data(const std::string s,const unsigned sd,const double r):bookno(s),units_sold(sd),revenue(r){}
Sales_data(std::istream& is);
Sales_data& combine(Sales_data& d);
std::string isbn()const
{
return bookno;
}
};
std::istream &read(std::istream& is, Sales_data& d);
std::ostream &print(std::ostream& os, const Sales_data& d);
Sales_data& add(Sales_data& d1, Sales_data& d2);
#endif
源文件:
#include<iostream>
#include"Sales_data.h"
using namespace std;
Sales_data& Sales_data::combine(Sales_data& d)
{
units_sold += d.units_sold;
revenue += d.revenue;
return *this;
}
std::istream& read(std::istream& is, Sales_data& d)
{
double price = 0.0;
is >> d.bookno >> d.units_sold >> price;
d.revenue = d.units_sold * price;
return is;
}
Sales_data& add(Sales_data& d1, Sales_data& d2)
{
Sales_data sum=d1;
sum.combine(d2);
return sum;
}
std::ostream& print(std::ostream& os, const Sales_data& d)
{
os << "isbn:" << d.isbn() << " " << " sells" << d.units_sold << " " << " and its revenue is: " << d.revenue << endl;
return os;
}
Sales_data::Sales_data(std::istream& is)
{
read(is, *this);
}
int main()
{
if (cin)
{
Sales_data total(cin);
Sales_data trans;
while (read(cin, trans))
{
if (total.isbn() == trans.isbn())
{
total.combine(trans);
}
else
{
print(cout, total)<<endl;
total = trans;
}
}
print(cout, total) << endl;
}
else
{
std::cerr << "No data!" << endl;
}
}
最后将构造函数放在类内部成功运行的程序代码:
头文件:
//头文件"Sales_data.h"
#ifndef SALESDATA
#define SALESDATA
#include<string>
struct Sales_data;
std::istream& read(std::istream& is, Sales_data& d);
struct Sales_data
{
std::string bookno;
unsigned units_sold = 0;
double revenue = 0.0;
Sales_data() = default;
Sales_data(const std::string s) :bookno(s) {}
Sales_data(const std::string s, const unsigned sd, const double r) :bookno(s), units_sold(sd), revenue(r) {}
Sales_data(std::istream& is)
{
read(is, *this);
}
Sales_data& combine(Sales_data& d);
std::string isbn()const
{
return bookno;
}
};
std::ostream& print(std::ostream& os, const Sales_data& d);
Sales_data& add(Sales_data& d1, Sales_data& d2);
#endif
源文件:
#include<iostream>
#include"Sales_data.h"
using namespace std;
Sales_data& Sales_data::combine(Sales_data& d)
{
units_sold += d.units_sold;
revenue += d.revenue;
return *this;
}
std::istream& read(std::istream& is, Sales_data& d)
{
double price = 0.0;
is >> d.bookno >> d.units_sold >> price;
d.revenue = d.units_sold * price;
return is;
}
Sales_data& add(Sales_data& d1, Sales_data& d2)
{
Sales_data sum = d1;
sum.combine(d2);
return sum;
}
std::ostream& print(std::ostream& os, const Sales_data& d)
{
os << "isbn:" << d.isbn() << " " << " sells" << d.units_sold << " " << " and its revenue is: " << d.revenue << endl;
return os;
}
int main()
{
if (cin)
{
Sales_data total(cin);
Sales_data trans;
while (read(cin, trans))
{
if (total.isbn() == trans.isbn())
{
total.combine(trans);
}
else
{
print(cout, total) << endl;
total = trans;
}
}
print(cout, total) << endl;
}
else
{
std::cerr << "No data!" << endl;
}
}