zoukankan      html  css  js  c++  java
  • 定义抽象数据类型

    在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
    20
    Sales_data total;//保存当前求和结果的变量
    if(read(cin,total))//读入第一笔交易
    {
        Sales_data trans;//保存下一条交易数据的变量
        while(read(cin,trans))//读入剩余交易
        {
            if(total.isbn()==trans.isbn())//检查isbn
                total.combine(trans);//更新变量total当前的值
            else
            {
                print(cout,total)<<endl;//输出结果
                total=trans;//处理下一本书
            }
        }
        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
    9
    struct 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
    3
    Sales_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属性。同时,类外部定义的成员的名字必须包含它所属的类名。

     

    作用域运算符::一旦编译器看到这个函数名,就能理解剩余的代码是位于类的作用域内的。

  • 相关阅读:
    清理git提交记录并不能达到真正硬盘“瘦身”
    virtualbox虚拟机异常暂停
    百兆带宽升千兆-番外篇
    流水文之百兆带宽升千兆
    OSS设置静态网站托管+CDN加速OSS域名
    每日一坑-exsi中win虚拟机调分辨率
    nginx筛选字段+excel统计
    树莓派使用Samba共享文件
    chrome无法使用独显解决
    解决jdk16安装后无jre目录的问题
  • 原文地址:https://www.cnblogs.com/yjds/p/8597247.html
Copyright © 2011-2022 走看看