c++类的基本思想是数据抽象和封装。数据抽象是一种依赖于接口和实现分离的编程(以及设计)技术。类的接口包括用户所能执行的操作:类的实现则包括类的数据成员、负责接口实现的函数体以及定义类所需的各种私有函数。
让我们举一个现实生活中的真实例子,比如一台电视机,您可以打开和关闭、切换频道、调整音量、添加外部组件(如喇叭、录像机、DVD 播放器),但是您不知道它的内部实现细节,也就是说,您并不知道它是如何通过缆线接收信号,如何转换信号,并最终显示在屏幕上。
因此,我们可以说电视把它的内部实现和外部接口分离开了,您无需知道它的内部实现原理,直接通过它的外部接口(比如电源按钮、遥控器、声量控制器)就可以操控电视。
现在,让我们言归正传,就 C++ 编程而言,C++ 类为数据抽象提供了可能。它们向外界提供了大量用于操作对象数据的公共方法,也就是说,外界实际上并不清楚类的内部实现。
先大致浏览一下代码,下面会进行详解
#include <cstdlib>
#include <string>
#include<iostream>
using namespace std;
//成员函数声明必须在类内,定义在类内,类外均可
class Sales_data
{
public:
//构造函数
Sales_data() = default;
Sales_data(const string &s):bookNo(s) {}
Sales_data(const string &s,unsigned n,double p):bookNo(s),units_sold(n),revenue(n*p){}//列表初始化
Sales_data(istream &is);
//对外的接口
string isbn() const {return bookNo;}
Sales_data& combine(const Sales_data&);
//对外公开的数据
string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
//nonmember functions,作为Sales_data的非成员接口函数,定义和声明都在类的外部
istream &read(istream &is,Sales_data &item)
{
double price = 0;
is>>item.bookNo>>item.units_sold>>price;
item.revenue = item.units_sold*price;
return is;
}
ostream &print(ostream &os,const Sales_data &item)//加const是为了防止误操作 修改传入的值
{
os<<item.isbn()<<" "<<item.units_sold<<" "<<item.revenue;
return os;
}
Sales_data add(const Sales_data &lhs,const Sales_data &rhs)
{
Sales_data sum =lhs;
sum.combine(rhs);
return sum;
}
//member functions
Sales_data::Sales_data(istream &is)
{
read(is,*this);
}
Sales_data& Sales_data::combine(const Sales_data &rhs)
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
int main()
{
Sales_data item1;
print(std::cout,item1)<<endl;
Sales_data item2("0-201");
print(std::cout,item2)<<endl;
Sales_data item3("0-201",3,20.00);
print(std::cout,item3)<<endl;
Sales_data item4(std::cin);
print(std::cout,item4)<<endl;
return 0;
}
上面在main主函数,创建Sales_data类的对象item1/2/3/4,分别与类内的构造函数相对应,传入实参值,构造函数以const 引用的形参来接受。
定义类相关的非成员函数
比如add , read , print等,尽管这些函数定义的操作从概念上来说属于类接口的组成部分,但他们实际上并不属于类本身。
定义read和print函数
istream &read(istream &is,Sales_data &item)
{
double price = 0;
is>>item.bookNo>>item.units_sold>>price;
item.revenue = item.units_sold*price;
return is;
}
ostream &print(ostream &os,const Sales_data &item)//加const是为了防止误操作 修改传入的值
{
os<<item.isbn()<<" "<<item.units_sold<<" "<<item.revenue;
return os;
}
第一点,read和print分别接受一个各自IO类型的引用作为其参数,这是因为IO类属于不能被拷贝的类型,因此我们智能通过引用来传递他们。而且哦,因为读取和写入的操作会改变交流的内容,所以两个函数接受的都是普通引用,而非对常量的引用
定义add函数
add函数接受两个Sales_data对象作为其参数,返回值是一个新的Sales_data,用于表示前两个对象的和
在函数体中,我们定义了一个新的Sales_data对象并将其命名为sum。sum用于存放两笔交易的和。我们用 lhs 的副本(引用)来初始化sum。默认情况下,拷贝类的对象其实拷贝的是对象的数据成员。在拷贝工作完成之后,sum的bookNo、units_sold和revenue将和lhs一致。接下来我们调用combine 函数,将rhs的units_sold和revenue添加给sum。最后,函数范围sum的副本。