C++ Primer Plus 笔记第十章

对象和类

OOP特性:

   1. 抽象

   2. 封装和数据隐藏

   3. 多态

   4. 继承

   5. 代码的可重用性

10.1 过程性编程和面向对象编程

   采用OOP方法时:

    1. 描述对象所需的数据以描述用户与数据交互所需的操作;

    2. 确定如何实现接口和数据存储

10.2 抽象和类

   抽象:

    类表示人们可以用类方法的公有接口对类对象执行操作,这是抽象;

    抽象是通往用户定义类型的捷径,C++中用户定义类型是实现抽象接口的类设计

  数据隐藏:

    类的数据成员可以是私有的(默认值),这意味着只能通过成员函数来访问这些数据,这是数据隐藏

  封装:

    实现的具体细节(如数据表示和方法的代码)都是隐藏的,这就是封装

   类型:

    1. 决定数据对象需要的内存数量

    2. 决定如何解释内存中的位(long 和 float 在内存中占用的位数相同,但将他们转换为数值的方法不同)

    3. 决定可使用数据对象执行的操作和方法

10.2.2 C++中的类

   类规范由两部分组成:

    类声明: 以数据成员的方式描述数据部分,以成员函数(方法)的方式描述公有接口

    类方法定义: 描述如何实现类成员函数

    简单地说,类声明提供了类的蓝图,而方法定义提供了细节

   什么是接口:

    接口是一个共享框架,供两个系统交互时使用;

    接口让程序员能编写与类对象交互的代码,从而让程序能够使用类对象

   类声明:

 1 #include<iostream>
 2 #include<cstring>
 3 
 4 class Stock
 5 {
 6 private:
 7     char company[30];
 8     int shares;
 9     double share_val;
10     double total_val;
11     void set_tot() { total_val = shares * share_val; }
12 public:
13     void acquire(const char*co, int n, double pr);
14     void buy(int num, double price);
15     void sell(int num, double price);
16     void update(double price);
17     void show();
18 };

   关键字 class 指出这些代码定义了一个类设计;

   Stock 成为一个新的类型名,能够声明 Stock 类型的变量,称为对象或实例:

    Stock sally;  // 创建 Stock 对象 sally

    Stock solly;  // 创建 Stock 对象 solly

   关键字 private 和 public 描述了对类成员访问控制:

    使用类对象的程序都可以直接访问共有部分;

    只能通过共有成员函数访问对象的私有成员;

    共有成员函数提供了对象和程序之间的接口;

   防止程序直接访问数据被称为数据隐藏:

    数据隐藏(将数据放在类的私有部分中)是一种封装;

    封装的另一个例子,将类函数定义和类声明放在不同的文件中

   数据项通常放在私有部分,组成类接口的成员函数放在共有部分;

   不必在类声明中使用关键字 private,因为这是类对象的默认访问控制

10.2.3 实现类成员函数

   类成员函数定义特征:

    1. 定义成员函数时,使用作用域解析操作符(::)来标识函数所属的类

    2. 类方法可以访问类的 private 组件

   将类声明放在头文件中,而将类成员函数定义放在单独的一个源代码文件中;

   定义位于类声明中的函数都将自动成为内联函数;   

   调用成员函数时,他将使用被调用他的对象的数据成员:

    所创建的每个新对象都有自己的存储空间,用于存储其内部变量和类成员;

    同一个类的所有对象共享同一组类方法,即每种方法只有一个副本

10.2.4 使用类

   C++ 的目标是使得使用类与使用基本的内置类型尽可能相同:

    要创建类对象,可以声明类变量,也可以使用 new 为类对象分配存储空间;

    可以把对象作为函数的参数和返回值,也可以将一个对象赋给另一个对象

   使用新类型,最关键的是要了解成员函数的功能,而不必考虑实现的细节

10.2.5 小结 

   类设计:

    1. 提供类声明

      class className

      {

       private:

        data member declarations      // 将数据放私有部分中可以保护数据的完整性,数据隐藏

       public:

        member function prototypes

      };

    2. 实现类成员函数

    3. 类成员函数(方法)通过类对象调用

      Bozo bozetta;

      cout << Bozetta.Retort();

实现文件:

   stock1.h 文件提供类声明:

 1 #ifndef STOCK1_H_
 2 #define STOCK1_H_
 3 class Stock
 4 {
 5 private:
 6     char company[30];
 7     int shares;
 8     double share_val;
 9     double total_val;
10     void set_tot() { total_val = shares * share_val; }
11 public:
12     Stock();
13     Stock(const char *co, int n = 0, double pr = 0.0);
14     ~Stock();
15 
16     void buy(int num, double price);
17     void sell(int num, double price);
18     void update(double price);
19     void show();
20 };
21 
22 #endif

    stock1.cpp 文件实现了类成员函数的定义

 1 #include<iostream>
 2 #include "stock1.h"
 3 
 4 Stock::Stock()
 5 {
 6     std::cout << "Default constructor called\n";
 7     std::strcpy(company, "no name");
 8     shares = 0;
 9     share_val = 0.0;
10     total_val = 0.0;
11 }
12 
13 Stock::Stock(const char *co, int n, double pr)
14 {
15     std::cout << "Constructor using " << co << " called\n";
16     std::strncpy(company, co, 29);
17     company[29] = '\0';
18 
19     if (n < 0)
20     {
21         std::cerr << "Number of shares can`t be negative; "
22             << company << " shares set to 0.\n";
23         shares = 0;
24     }
25     else
26         shares = n;
27     share_val = pr;
28     set_tot();
29 }
30 
31 Stock::~Stock()
32 {
33     std::cout << "Bye, " << company << "!\n";
34 }
35 
36 void Stock::buy(int num, double price)
37 {
38     if (num < 0)
39     {
40         std::cerr << "Number of shares purchased can`t be negative. "
41             << "Transaction is aborted.\n";
42     }
43     else
44     {
45         shares += num;
46         share_val = price;
47         set_tot();
48     }
49 }
50 
51 void Stock::sell(int num, double price)
52 {
53     using std::cerr;
54     if (num < 0)
55     {
56         std::cerr << "Number of shares purchased can`t be negative. "
57             << "Transaction is aborted.\n";
58     }
59     else if (num > shares)
60     {
61         cerr << "You can`t sell more than you have! "
62             << "Transaction is aborted.\n";
63     }
64     else
65     {
66         shares -= num;
67         share_val = price;
68         set_tot();
69     }
70 }
71 
72 void Stock::update(double price)
73 {
74     share_val = price;
75     set_tot();
76 }
77 
78 void Stock::show()
79 {
80     std::cout << "company: " << company
81         << " shares: " << shares << std::endl
82         << " share price: $" << share_val
83         << " Total Worth: $" << total_val << std::endl;
84 }

    usestock1.cpp 文件测试

 1 #include<iostream>
 2 #include "stock1.h"
 3 
 4 int main()
 5 {
 6     using std::cout;
 7     using std::ios_base;
 8     cout.precision(2);
 9     cout.setf(ios_base::fixed, ios_base::floatfield);
10     cout.setf(ios_base::showpoint);
11 
12     cout << "Using constructors to ctreat new objects\n";
13     Stock stock1("NanoSmart", 12, 20.0);
14     stock1.show();
15 
16     Stock stock2 = Stock("Boffo Objects", 2, 2.0);
17     stock2.show();
18 
19     Stock stock3;
20     stock3.show();
21 
22     return 0;
23 }

 10.3.6 构造函数和析构函数小结

   构造函数在创建类时被调用;

   构造函数的名称和类名称相同,通过函数重载可以创建多个同名的构造函数;

   构造函数没有声明类型;

   构造函数用于初始化类对象的成员:

    原型: Bozo ( const char * fname, const char * lname );

   初始化: Boza bozetta = Bozo ( "Bozetta", "Biggens" );

        Bozo fufu ( "Fufu", "O`Dweeb" );

           Bozo *pc = new Bozo ("Popo", "Le Peu"); 

   记住: 接受一个参数的构造函数允许使用赋值句法来将对象初始化为一个值  

      Classname object = value;

   默认构造函数没有参数,如果创建对象没有显示地初始化,则将调用默认构造函数;

   如果程序中没有任何构造函数,则编译器会为程序定义一个默认构造函数;

   对象被创建时调用构造函数,被删除时,程序调用析构函数:

    每个类只能有一个构造函数;

    析构函数没有声明类型,也没有参数,其名称为类名称前加上 ~;

    ~Bozo ();

    如果构造函数使用了 new,则必须提供使用 delete 的析构函数

10.4 this 指针

   有时候方法设计两个对象,在这种情况下需要使用C++的this指针;

   const Stock & topval ( const Stock & s) const;

   top = stock1.toval (stock2):

    函数隐式访问 stock1,显示访问 stock2;

    原型括号中的 const 表示,函数不会修改被显示地访问的对象;

    原型括号后的 const 表示,函数不会修改被隐式地访问的对象

    const Stock & Stock :: topval (const Stock & s) const

    {

      if (s.total_val > total_val)

        return s;

      else

        return *this;

    }

10.5 对象数组

   创建同一个类的多个对象,可以创建对象数组;

   声明对象数组的方法与声明标准类型数组相同:

    Stock mystuff [4];

   初始化对象数组的方案是,首先使用默认构造函数创建数组元素,然后使用括号中的构造函数创建临时对象,然后将临时对象的内容复制到相应的元素中;

   警告: 要创建类对象数组,则这个类必须有默认构造函数   

10.6 接口和实现小结

   修改类的私有部分和实现文件属于实现变更,实现变更改变了类的内部工作原理;

   修改类的公有部分属于接口变更,接口变更改变了使用类的人可用的编码方式;

10.7 类的作用域

   在类中定义的名称(类数据成员或类函数成员)作用域为整个类;

   类作用域意味着不能从外部直接访问类的成员,要调用类的公有成员必须通过对象:

    Stock sleeper ("Exclusive Ore", 100, 0.25);  // 创建对象

    sleeper.show()   // 使用对象调用成员函数

   在定义成员函数时,必须使用作用域解析操作符:

    void Stock :: update(double price)

    {

       .  .  .  

    }

    在类声明或成员函数定义中,可以使用未修饰的成员名称(未限定名称);

    其他情况下,使用类成员名时:

      直接成员操作符(.);         // 对象

      间接成员操作符(->);    // 指针

      作用域解析操作符(::);  // 定义成员函数

   作用域为整个类的常量:

    1. 在类中声明一个枚举

      在类中声明的枚举的作用域为整个类;

      可以用枚举为整型常量提供作用域为整个类的符号名称:

        class Stock

        {

        private:

          enum {Len = 30};

          char company [Len];

          .  .  .

        }

      这种方式声明枚举并不会创建类成员,对象中不包含枚举;

      Len 只是一个符号名称,编译器将用 30 替换

    2. C++ 引入另一种在类中定义常量的方式——使用关键字 static:

      class Stock

      {

      private:

        static const int Len = 30;

        char company [Len];

        .  .  .

      }

      这里创建一个名为 Len 的常量,该常量与其他静态变量存储在一起,而不存在对象中;

      只有一个 Len 常量,被所有 Stock 对象所共享

10.8 抽象数据类型

   ADT以通用的方式描述数据类型,而没有引入语言或实现细节

10.9 总结

   类是用户定义的类型,对象是类的实例;

   C++ 试图让用户定义的类型尽可能与标注类型类似,因此可以声明对象、指向对象的指针和对象数组;

   

            

    

 

 

 

 

 

    

   

posted @ 2018-10-04 18:49  KidyCharon  阅读(354)  评论(0编辑  收藏  举报