Sales_data类实现 及 类特性

实现Sales_data

#include <iostream>
#include <string>
class Sales_data {
	friend std::istream& operator >> (std::istream&, Sales_data&);
	friend std::ostream& operator << (std::ostream&,const Sales_data&);
	friend bool operator == (const Sales_data&, const Sales_data&);
	public: //重载类的+=运算符
		Sales_data& operator += (const Sales_data&);
		std::string isbn() const { return bookNo; }
	public:
		Sales_data() = default; //显式声明默认构造函数
		Sales_data(const std::string& book) :bookNo(book){}
		Sales_data(std::istream& is) { is >> *this; }
	private:
		std::string bookNo;
		unsigned units_sold = 0;
		double sellingprice = 0.0;
		double saleprice = 0.0;
		double discount = 0.0;
};
//好习惯: 现将友元函数声明
std::istream& operator >> (std::istream&, Sales_data&);
std::ostream& operator << (std::ostream&, const Sales_data&);
bool operator == (const Sales_data&, const Sales_data&);
//全局函数.
inline bool compareIsbn(const Sales_data& lhs, const Sales_data& rhs) {
	return lhs.isbn() == rhs.isbn();
}
inline bool operator == (const Sales_data& lhs, const Sales_data& rhs) {
	return lhs.units_sold == rhs.units_sold &&
		lhs.sellingprice == rhs.sellingprice &&
		lhs.saleprice == rhs.saleprice &&
		lhs.isbn() == rhs.isbn();
}
inline bool operator != (const Sales_data& lhs, const Sales_data& rhs) {
	return !(lhs == rhs);
}
Sales_data& Sales_data::operator += (const Sales_data& rhs) {
	units_sold += rhs.units_sold;
	saleprice = (rhs.saleprice * rhs.units_sold + saleprice * units_sold) / (rhs.units_sold + units_sold);
	if (sellingprice != 0)
		discount = saleprice / sellingprice;
	return *this;
}
Sales_data operator + (const Sales_data& lhs, const Sales_data& rhs) {
	Sales_data ret(lhs);
	ret += rhs;
	return ret; //如果返回引用,临时对象内存被销毁,引用没意义,只能返回临时对象的拷贝
}
std::istream& operator >> (std::istream& in, Sales_data& s) {
	in >> s.bookNo >> s.units_sold >> s.sellingprice >> s.saleprice;
	if (in && s.sellingprice != 0)
		s.discount = s.saleprice / s.sellingprice;
	else
		s = Sales_data();//默认构造
	return in;
}
std::ostream& operator << (std::ostream& out,const Sales_data& s) {
	out << s.isbn() << " " << s.units_sold << " " << s.sellingprice << " " << s.saleprice << " " << s.discount;
	return out;
}
int main() {
	Sales_data trans1, trans2;
	std::cout << "输入2条相同的ISBN销售记录: " << std::endl;
	std::cin >> trans1 >> trans2;
	if (compareIsbn(trans1, trans2))
		std::cout << "汇总信息: ISBN,售出本数,原始价格,实际价格,折扣:" << trans1 + trans2 << std::endl;
	else std::cout << "2条销售记录ISBN不相同 " << std::endl;
	Sales_data total, trans;
	std::cout << " 请输入几条ISBN相同的销售记录: " << std::endl;
	if (std::cin >> total) {
		while (std::cin >> trans) {
			if (compareIsbn(total, trans))
				total += trans;
			else {
				std::cout << " 当前书的ISBN不同 " << std::endl;
				break;
			}
		}
		std::cout << "有效汇总信息: ISBN,售出书本,原始价格,实际价格,折扣:" << total << std::endl;
	}
	else {
		std::cout << " 没有数据 " << std::endl;
		return -1;
	}
	return 0;
}

构造函数初始值列表

  • 为数据成员赋初值,赋值的顺序根据数据成员定义的顺序

=default要求编译器生成默认构造函数

Sales_data() = default;

this的引入

  • obj.isbn() //成员函数的调用,成员函数通过名为this的额外隐式参数来访问调用它的对象,调用一个成员函数时,用请求该函数的对象地址初始化this
  • 从编译器角度等价于Sales_data::isbn(&obj);.
  • 我们能在成员函数内部直接调用该函数对象的成员就是通过this实现的,被看做是this的隐式引用,

this本身是一个常量指针 (不要和指向常量的指针混淆).

  • 常量指针即:指针存的地址是不变的,
  • 指向常量的指针即:指向的对象是不变的
  • 所以不能改变this保存的地址

const成员函数

std::string isbn() const { return bookNo; }

  • 相当于隐式修改this的类型,本来是常量指针Sales_data * const
  • 现在是const Sales_data * const,指向常量的常量指针,意味着指向的对象是常量,如果该函数不需要修改对象的数据成员,那么const成员函数很有必要,

类的作用域Sales_data::, 全局作用域::

  • 如果isbn()定义在类的外部.std::string Sales_data::isbn() const { return bookNo; }
  • 那么在Sales_data::之后都属于类的作用域内,如果isbn()要返回类中定义的变量类型,那么返回值要声明作用域

定义返回this对象的函数

Sales_data& operator += (const Sales_data&);
//用一个函数代替重载+=的效果
Sales_data& Sales_data::combine(const Sales_data &rhs) {
    units_sold += rhs.units_sold;
    return *this; //解引用返回this绑定对象本身
}
//使用combine时,total绑定到this上,trans 绑定到 rhs上,
total.combine(trans);

  • 结果都加到total中,因为定义的函数类似+=运算符,左边的运算对象作为左值返回,必须与左值返回保持一致,所以要返回total对象本身
  • 如果返回类型是Sales_data,相当于通过拷贝创建了一个临时对象然后返回.

访问控制符 access specifiers

  • classstruct的区别在于 第一个访问控制符出现之前 class的默认权限是private,而struct的权限是public
  • private的数据成员只能被类的成员函数访问,而使用该类的代码不能访问,需要在public中提供接口,private相当于封装了类的实现细节

友元

  • 其他类或者函数访问它的非公有成员,方法是声明其他类或函数成为该类的友元(friend)
  • 友元函数的声明,仅仅是声明了友元的关系,并不是函数声明.

类成员

  1. 定义类型成员,别名(alias)作用范围从定义开始
class Screen {
    public:
        typedef std::string::size_type pos;
        // using pos=std::string::size_type;
};
  • 在类外使用类的类型成员要说明作用域

inline是否展开取决于编译器

构造函数的默认实参

Sales_data(std::string s = ""):bookNo(s) {}
  • 使用实参来初始化bookNo,不接受参数就默认string初始化

委托构造函数

  • 委托构造函数使用所属类的其他构造函数来执行自己的初始化过程,
  • 先执行所委托给的构造函数,然后再来执行自己函数体的内容
Sales_data(std::string s,unsigned cnt,double sellp,double salep) : bookNo(s),units_sold(cnt),sellingprice(sellp),saleprice(salep){}
Sales_data() : Sales_data("", 0, 0.0, 0.0) {}
Sales_data(std::istream& is) :Sales_data() { is >> *this; }
  • 委托构造函数能够多层委托,可以委托给一个已经是委托构造函数的函数,从受委托的构造函数开始依次执行代码.最后才返回到委托者自身函数体

使用默认构造函数

Sales_data obj(); //错误,声明了一个返回值是Sales_data的函数
Sales_data obj; //调用默认构造

隐式类型转换规则 (关键字:explicit)

  • 只存在于 接收一个实参的构造函数,默认就定义了为此类类型的隐式转换机制
在需要使用Sales_data的地方,使用接收一个参数的构造函数的参数类型作为替代,能隐式转化成Sales_data类型
//如果:
Class Sales_data {
    public:
        Sales_data& combine(Sales_data&);
};

string ss = "aaa";
total.combine(ss); //combine另一个Sales_data的对象,这里用string对象替代
//编译器用string对象创建了一个Sales_data对象,这个生成的Sales_data临时对象作为参数传给combine
  • 只能从一个参数的构造函数的参数类型转换到Sales_data
total.combine("dads"); //"dads"是c风格的字符串 char[],不是string对象
total.combine(string("abc")); //转化成string
total.combine(Sales_data("abc")); //直接转化成Sales_data对象

抑制构造函数定义的隐式类型转换 explicit :明白的

  • 只在接收一个参数的构造函数中定义了隐式类型转换,即使对于多个参数构造函数声明了也没意义
class Sales_data {
  public:
    Sales_data() = default;
    Sales_data(const std::string &s,unsigned n,double p1,double p2):
        bookNo(s),units_sold(n),sellingprice(p1),saleprice(p2) {}
    explicit Sales_data(const std::string &s) : bookNo(s) {}
    explicit Sales_data(std::istream&);
};
  • 函数在类外部定义时不需要再次声明explicit
  • 拷贝初始化
std::string temp = "acx";
Sales_data item(temp);
Sales_data item = temp; //拷贝形式,隐式转换成Sales_data
  • 强制类型转换
item.combine(Sales_data(temp));
item.combine(static_cast<Sales_data>(cin));
item.combine(static_cast<Sales_data>(temp));

友元部分的理解,(最好在友元函数实现前,声明一次,有点编译器需要声明)

friend std::istream& operator >> (std::istream&, Sales_data&);
friend std::ostream& operator << (std::ostream&,const Sales_data&);
friend bool operator == (const Sales_data&, const Sales_data&);
  • 在全局作用域内重载>><<运算符,友元的目的是访问到Sales_data对象的private成员

istream ostream输入输出流的使用

  • cincout分别是iostream类和ostream的对象
  • 接收流的引用,特别要注意返回流的引用
std::istream& operator >> (std::istream& in, Sales_data& s) {
	in >> s.bookNo >> s.units_sold >> s.sellingprice >> s.saleprice;
	if (in && s.sellingprice != 0)
		s.discount = s.saleprice / s.sellingprice;
	else
		s = Sales_data();//默认构造
	return in;
}
std::ostream& operator << (std::ostream& out,const Sales_data& s) {
	out << s.isbn() << " " << s.units_sold << " " << s.sellingprice << " " << s.saleprice << " " << s.discount;
	return out;
}
  • 构造函数接收的输入流对象参数,那么想要通过流来初始化对象一定要重载>>
    Sales_data(std::istream& is) { is >> *this; }
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值