定义抽象数据类型
在C++语⾔中,我们使⽤类定义⾃⼰的数据类型。通过定义新的类型来反映待解决问题中的各种概念,可以使我们更容易编写,调试,和修改程序。
类的基本思想是数据抽象和封装。数据抽象是⼀种依赖于接⼝和实现分离的编程技术。累得接⼝包括⽤户所能执⾏的操作;类的实现则包括类的数据成员、负责接⼝实现的函数体以及类所需的各种私有函数。
封装实现了类的接⼝和实现的分离。封装后的类隐藏了他的实现细节,也就是说,类的⽤户只能使⽤接⼝⽽⽆法访问实现的部分。
类要想实现数据抽象个封装,需要⾸先定义⼀个抽象数据类型。在抽象数据类型中,由类的设计者负责考虑类的实现过程,使⽤该类的程序员则只需要抽象的思考类型做了什么,⽽⽆需了解类型的⼯作细节。
1、定义抽象数据类型:
(1)设计sales_data类:
我们的最终⽬的是令sales_data⽀持与sales_items类完全⼀样的操作集合。sales_items有⼀个名为isbn的成员函数,并且⽀持+-×/等运算符。
注意:我们将在14章学习如何⾃定义运算符。现在我们先为这些运算定义普通函数形式。
综上,sales_data的接⼝因该包含以下操作:
『』⼀个isbn成员函数,⽤于返回isbn编号
『』⼀个combine成员函数,⽤于将⼀个sales_data对象加到另⼀个对象上。
『』⼀个名为add的函数,执⾏两个sales_data对象的加法
『』⼀个read函数,将数据从istream读⼊到sales_data对象中
『』⼀个print函数,将sales_data对象的值输出到ostream
关键概念:不同的编程⾓⾊
程序员把运⾏程序的⼈称作⽤户(user)。类似的,类的设计者也是为其⽤户设计并实现⼀个类的⼈:显然类的⽤户是程序员,⽽⾮应⽤程序的最终使⽤者。
使⽤改进sales_data类:
在考虑如何实现类之前,⾸先来看看如何使⽤上⾯这些接⼝函数。
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20Sales_data total;//保存当前求和结果的变量
if(read(cin,total))//读⼊第⼀笔交易
{
Sales_data trans;//保存下⼀条交易数据的变量
while(read(cin,trans))//读⼊剩余交易
{
if(total.isbn()==trans.isbn())//检查isbn
totalbine(trans);//更新变量total当前的值        else
{
print(cout,total)<<endl;//输出结果
total=trans;//处理下⼀本书
}
}
const的作用
print(cout,total)<<endl;//输出最后⼀条交易
}
else//没有输⼊任何信息
{
cerr<<"no data?!"<<endl;//通知⽤户
}
1. #include <iostream>
2. #include<string>
3. #include<vector>
4. using namespace std;
5. /*
6. C++ 中保留了C语⾔的 struct 关键字,并且加以扩充。在C语⾔中,struct 只能包含成员变量,不能包含成员函数。
7. ⽽在C++中,struct 类似于 class,既可以包含成员变量,⼜可以包含成员函数。
8.
9. C++中的 struct 和 class 基本是通⽤的,唯有⼏个细节不同:
10. 1:使⽤ class 时,类中的成员默认都是 private 属性的;⽽使⽤ struct 时,结构体中的成员默认都是 public 属性的。(最本质的区别)
11. 2:class 继承默认是 private 继承,⽽ struct 继承默认是 public 继承(《C++继承与派⽣》⼀章会讲解继承)。
12. 3:class 可以使⽤模板,⽽ struct 不能。
13. */
14.
15. //利⽤class定义类
16. class Student
17. {
18.    Student(string name, int age, int score);//构造函数
19.
20.    string m_name;
21.    int m_age;
22.    int m_score;//定义三个变量
23.
24.    void showname()//定义⼀个函数
25.    {
26.        cout<<m_name<<"的年龄是:"<<m_age<<",得分为:"<<m_score<<endl;
27.    }//类内定义的函数,编译器会优先视为内联函数
28. public:
29. private:
30. protected://三种形式
31. };
32. Student::Student(string name, int age, int score):m_name(name), m_age(age), m_score(score){ }
33. //成员初始化列表,将name赋给m_name,改变类内变量
34.
35.
36. //利⽤strcut定义类
37. struct Students
38. {
39.    Students(string name, int age, int score);//构造函数
40.
41.    string m_name;
42.    int m_age;
43.    int m_score;//定义三个变量,默认public
44.
45.    void shownames()//定义⼀个函数
46.    {
47.        cout<<m_name<<"的年龄是:"<<m_age<<",得分为:"<<m_score<<endl;
48.    }//类内类外定义皆是在同⽂件中,也可定义在.h⽂件中。
49. };
50. Students::Students(string name, int age, int score):m_name(name), m_age(age), m_score(score){ }
51. //列表初始化,覆盖类的内部变量
52.
53. /*
54. 总结
55. 1:struct作为数据结构的实现体,它默认的数据访问控制是public的,⽽class作为对象的实现体,它默认的成员变量访问控制是
private的
56. 2:当你觉得你要做的更像是⼀种数据结构的话,那么⽤struct,如果你要做的更像是⼀种对象的话,那么⽤class。
57. 3:然⽽对于访问控制,应该在程序⾥明确的指出,⽽不是依靠默认,这是⼀个良好的习惯,也让你的代码更具可读性。
58. */
59.
60. int main(int argc, char** argv)
61. {
62.    Student stu1("⼩明", 18, 3);//报错:虽然已声明,但是不可访问。成员没有限定public,默认都是private,外部不可访问。
63.    Students stu2("⼩明", 18, 3);//正常
64.    stu2.shownames();
65.    return 0;
66. }
2、定义改进的sales_data类:
改进之后的类的数据成员将与之前保持⼀致。
类将包含两个成员函数:combine和isbn。此外,我们还将赋予sales_data另外⼀个成员函数⽤于返回售出书记的平均价格,这个函数被命名为avg_price。因为avg_price的⽬的并⾮通⽤,所以它应该属于类的实现的⼀部分,⽽⾮接⼝的⼀部分。
成员函数的声明必须在类的内部,它的定义则能在类的内部也可以在外部。作为接⼝组成部分的⾮成员函数,例如:add,read,print等,他们的定义和声明都在类的外部:
1 2 3 4 5 6 7 8 9struct Sales_data
{
std::string isbn()const{return bookno;}
Sales_data & combine(const Sales_data&);        double avg_price() const;
std::string bookno;
unsigned units_sold=0;
double revenue =0.0;
};
1 2 3Sales_data add(const Sales_data &, const Sales_data &); std::ostream &print(std::ostream&, const Sales_data &); std::istream &read(std::istream&, Sales_data &);
注意定义在类内部的函数是隐式的inline函数。
⾸先介绍,isbn函数,它的参数列表为空,返回值是⼀个string对象,成员函数体也是⼀个块。在isbn中快只有⼀条return语句,⽤于返回sales_data对象的bookno数据成员。关于isbn函数⼀件有意思的事
情是:它是如何获得bookno数据成员的那。
在成员内部,我们可以直接使⽤调⽤该函数的对象的成员,⽽⽆需通过成员访问运算符来做到这⼀点,因为this所指的正是这个对象。任何对类的直接访问都被看作this的隐式引⽤,也就是当isbn使⽤bookno时,他隐式的使⽤this指向的成员,就像我们书写了this->bookno⼀样。
引⼊const成员函数:
isbn函数的另外⼀个关键之处是紧随参数列表之后的const关键字,这⾥,const的作⽤是修改隐式this指针类型。
默认情况下,this的类型是指向类类型⾮常量版本的常量指针。例如在sales_data成员函数中,this的类型是sales_data *const。尽管this是隐式的,但它仍然需要遵循初始化规则,意味着我们不能把this绑定到⼀个常量对象上。这⼀情况也就使我们不能吧this绑定到⼀个常量对象上。使我们不能在⼀个常量对象上调⽤普通的成员函数。
在C++中,把const关键字放在成员函数的参数列表之后,此时,紧跟在参数列表后⾯的const表⽰this是⼀个指向常量的指针。像这样使⽤const的成员函数被称作常量成员函数。
常量对象,以及常量对象的引⽤或指针都只能调⽤常量成员函数。
类作⽤域和成员函数:
类本⾝就是⼀个作⽤域,类的成员函数的定义嵌套在类的作⽤域之内,因此,isbn中⽤到的名字bookno其实就是定义在sales_data内的数据成员。
在类的外部定义成员函数:
像其他函数⼀样,在类的外部定义成员函数时,成员函数的定义必须与他的⽣命匹配。也就是说,返回类型,参数列表,函数名都与类内部的声明保持⼀致。如果成员被声明称常量成员函数,那么他的定义也必须在参数列表后明确的制定const属性。同时,类外部定义的成员的名字必须包含它所属的类名。
作⽤域运算符::⼀旦编译器看到这个函数名,就能理解剩余的代码是位于类的作⽤域内的。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。